2668 lines
No EOL
71 KiB
C++
2668 lines
No EOL
71 KiB
C++
#include "stdafx.h"
|
|
#include "DNScriptAPICommon.h"
|
|
#include "DnLuaAPIDefine.h"
|
|
#include "DNGameDataManager.h"
|
|
#include "DNQuestManager.h"
|
|
#include "DNUserSession.h"
|
|
#include "DNNpc.h"
|
|
#include "DNReplaceString.h"
|
|
#include "EtUIXML.h"
|
|
#if defined( PRE_ADD_NPC_REPUTATION_SYSTEM )
|
|
#include "ReputationSystemRepository.h"
|
|
#include "NpcReputationProcessor.h"
|
|
#endif // #if defined( PRE_ADD_NPC_REPUTATION_SYSTEM )
|
|
|
|
#include "DNQuest.h"
|
|
|
|
#if defined (_GAMESERVER)
|
|
#include "DnPlayerActor.h"
|
|
#endif
|
|
|
|
#if defined(_VILLAGESERVER) && defined( PRE_DRAGONBUFF )
|
|
#include "DNUserSessionManager.h"
|
|
#include "DNMasterConnection.h"
|
|
#endif
|
|
|
|
extern CLog g_ScriptLog;
|
|
|
|
namespace DNScriptAPI
|
|
{
|
|
// desc : 인벤토리의 특정 빈슬롯에 아이템을 세팅 (P.S.> api_user_CheckInvenForAddItemList 에서 사용됨)
|
|
bool __SetBlankInventorySlot(TInvenItemCnt pTempInven[INVENTORYMAX], const TItem& Item, int iIndex)
|
|
{
|
|
DN_ASSERT(NULL != pTempInven, "Invalid!");
|
|
DN_ASSERT(0 != Item.nItemID, "Invalid!");
|
|
DN_ASSERT(0 < Item.wCount, "Invalid!");
|
|
DN_ASSERT(-1 < iIndex, "Invalid!");
|
|
|
|
if (pTempInven[iIndex].nItemID != 0) {
|
|
return false;
|
|
}
|
|
|
|
pTempInven[iIndex].Set( Item.nItemID, Item.wCount, Item.bSoulbound, Item.cSealCount );
|
|
|
|
return true;
|
|
}
|
|
|
|
// desc : 인벤토리의 빈슬롯들에 아이템을 특정 개수만큼 세팅 (P.S.> api_user_CheckInvenForAddItemList 에서 사용됨)
|
|
bool __SetBlankInventorySlotCount(TInvenItemCnt pTempInven[INVENTORYMAX], const TItem& Item, int nOverlapCount, int nCount /* 채울 슬롯개수 */)
|
|
{
|
|
DN_ASSERT(NULL != pTempInven, "Invalid!");
|
|
DN_ASSERT(0 != Item.nItemID, "Invalid!");
|
|
DN_ASSERT(0 < Item.wCount, "Invalid!");
|
|
DN_ASSERT(0 < nOverlapCount, "Invalid!");
|
|
DN_ASSERT(0 < nCount, "Invalid!");
|
|
|
|
// !!! 주의 - 본 함수 호출 전에 체크가 확실히 되었음을 전제하고 세팅하는 부분만 수행
|
|
|
|
int nBundle = Item.wCount / nOverlapCount;
|
|
int nRemain = Item.wCount % nOverlapCount;
|
|
|
|
for (int iIndex = 0 ; INVENTORYMAX > iIndex ; ++iIndex)
|
|
{
|
|
if (0 < nBundle) {
|
|
if (pTempInven[iIndex].nItemID == 0)
|
|
{
|
|
pTempInven[iIndex].Set( Item.nItemID, nOverlapCount, Item.bSoulbound, Item.cSealCount );
|
|
--nBundle;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (0 < nRemain)
|
|
{
|
|
if( CDNUserItem::bIsSameItem( &Item, &pTempInven[iIndex] ) && nOverlapCount >= pTempInven[iIndex].wCount + nRemain )
|
|
{
|
|
pTempInven[iIndex].wCount += nRemain;
|
|
nRemain = 0;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (0 < nBundle)
|
|
{
|
|
return false;
|
|
}
|
|
if (0 < nRemain)
|
|
{
|
|
for (int iIndex = 0 ; INVENTORYMAX > iIndex ; ++iIndex)
|
|
{
|
|
if (pTempInven[iIndex].nItemID == 0) {
|
|
pTempInven[iIndex].Set( Item.nItemID, nRemain, Item.bSoulbound, Item.cSealCount );
|
|
nRemain = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (0 < nRemain)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// desc : 인벤토리의 특정 슬롯에 아이템을 중첩 세팅 (P.S.> api_user_CheckInvenForAddItemList 에서 사용됨)
|
|
bool __SetOverlapInventorySlot(TInvenItemCnt pTempInven[INVENTORYMAX], const TItem& Item, int nOverlapCount, int iIndex)
|
|
{
|
|
DN_ASSERT(NULL != pTempInven, "Invalid!");
|
|
DN_ASSERT(0 != Item.nItemID, "Invalid!");
|
|
DN_ASSERT(0 < Item.wCount, "Invalid!");
|
|
DN_ASSERT(0 < nOverlapCount, "Invalid!");
|
|
DN_ASSERT(-1 < iIndex, "Invalid!");
|
|
|
|
if ( CDNUserItem::bIsDifferentItem( &Item, &pTempInven[iIndex] ) || nOverlapCount < pTempInven[iIndex].wCount + Item.wCount )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
pTempInven[iIndex].wCount += Item.wCount;
|
|
|
|
return true;
|
|
}
|
|
|
|
// desc : 인벤토리에 빈슬롯 찾기 (P.S.> api_user_CheckInvenForAddItemList 에서 사용됨)
|
|
int __FindBlankInventorySlot(TInvenItemCnt pTempInven[INVENTORYMAX], int nTempInvenCount)
|
|
{
|
|
DN_ASSERT(NULL != pTempInven, "Invalid!");
|
|
DN_ASSERT(CHECK_RANGE(nTempInvenCount, 0, INVENTORYMAX), "Invalid!");
|
|
|
|
for (int iIndex = 0 ; nTempInvenCount > iIndex ; ++iIndex) {
|
|
if (pTempInven[iIndex].nItemID == 0) {
|
|
return iIndex;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// desc : 인벤토리에 빈슬롯이 몇 개나 있는지 개수 찾기 (P.S.> api_user_CheckInvenForAddItemList 에서 사용됨)
|
|
int __FindBlankInventorySlotCount(TInvenItemCnt pTempInven[INVENTORYMAX], int nTempInvenCount)
|
|
{
|
|
DN_ASSERT(NULL != pTempInven, "Invalid!");
|
|
DN_ASSERT(CHECK_RANGE(nTempInvenCount, 0, INVENTORYMAX), "Invalid!");
|
|
|
|
int nCount = 0;
|
|
for (int iIndex = 0 ; nTempInvenCount > iIndex ; ++iIndex) {
|
|
if (pTempInven[iIndex].nItemID == 0) {
|
|
++nCount;
|
|
}
|
|
}
|
|
|
|
return nCount;
|
|
}
|
|
|
|
// desc : 인벤토리에 셀 수 있는 아이템 중 남은 공간에 wCount 넣을 수 있는 Index 찾기 (P.S.> api_user_CheckInvenForAddItemList 에서 사용됨)
|
|
int __FindOverlapInventorySlot(TInvenItemCnt pTempInven[INVENTORYMAX], int nTempInvenCount, const TItem& Item)
|
|
{
|
|
DN_ASSERT(NULL != pTempInven, "Invalid!");
|
|
DN_ASSERT(CHECK_RANGE(nTempInvenCount, 0, INVENTORYMAX), "Invalid!");
|
|
|
|
if ((Item.nItemID <= 0) || (Item.wCount <= 0)) DN_RETURN(-1);
|
|
|
|
TItemData *pItemData = NULL;
|
|
for (int iIndex = 0 ; nTempInvenCount > iIndex ; ++iIndex) {
|
|
if (pTempInven[iIndex].nItemID == 0) {
|
|
// 빈칸이면 패스
|
|
continue;
|
|
}
|
|
|
|
pItemData = g_pDataManager->GetItemData(pTempInven[iIndex].nItemID);
|
|
if (!pItemData) continue;
|
|
|
|
if (pItemData->nOverlapCount == 1) continue; // 겹치지 않으면 패스
|
|
if( CDNUserItem::bIsDifferentItem( &Item, &pTempInven[iIndex] ) ) continue; // 같은 아이템이 아님
|
|
|
|
if (pItemData->nOverlapCount >= pTempInven[iIndex].wCount + Item.wCount) {
|
|
return iIndex;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// desc : 인벤토리에 아이템을 넣을 수 있는 공간이 충분한지 검사 (P.S.> api_user_CheckInvenForAddItemList 에서 사용됨)
|
|
bool __IsValidSpaceInventorySlotAndSet(TInvenItemCnt pTempInven[INVENTORYMAX], int nTempInvenCount, const TItem& Item )
|
|
{
|
|
DN_ASSERT(NULL != pTempInven, "Invalid!");
|
|
DN_ASSERT(CHECK_RANGE(nTempInvenCount, 0, INVENTORYMAX), "Invalid!");
|
|
|
|
if ((Item.nItemID <= 0) || (Item.wCount <= 0))
|
|
DN_RETURN(false);
|
|
|
|
TItemData *pItem = g_pDataManager->GetItemData(Item.nItemID);
|
|
if (!pItem) return false;
|
|
|
|
#if defined (_VILLAGESERVER)
|
|
if (ITEMTYPE_QUEST == pItem->nType) {
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
int nCount = 0;
|
|
if (pItem->nOverlapCount == 1){ // 겹치지 않는 아이템
|
|
nCount = __FindBlankInventorySlotCount(pTempInven, nTempInvenCount);
|
|
if (Item.wCount > nCount) {
|
|
// 빈슬롯이랑 비교하기
|
|
return false;
|
|
}
|
|
|
|
return(__SetBlankInventorySlotCount(pTempInven, Item, 1, nCount));
|
|
}
|
|
else {
|
|
// 겹쳐지는 아이템 (인벤에 동일 아이템들이 몇개씩 남아있어도 신경안쓰고 깔끔하게 넣는 경우만 생각하쟈)
|
|
if (pItem->nOverlapCount < Item.wCount){ // 한번에 겹치는 양보다 많을경우
|
|
int nBundle = Item.wCount / pItem->nOverlapCount;
|
|
if ((Item.wCount % pItem->nOverlapCount) > 0) nBundle++;
|
|
|
|
nCount = __FindBlankInventorySlotCount(pTempInven, nTempInvenCount);
|
|
if (nBundle > nCount) {
|
|
// 묶음이랑 빈슬롯이랑 비교하기
|
|
return false;
|
|
}
|
|
|
|
return(__SetBlankInventorySlotCount(pTempInven, Item, pItem->nOverlapCount, nCount));
|
|
}
|
|
else {
|
|
int nBlank = __FindOverlapInventorySlot(pTempInven, nTempInvenCount, Item ); // 기존 아이템중에 한방에 들어갈 아이템이 있는지
|
|
if (nBlank < 0){
|
|
nBlank = __FindBlankInventorySlot(pTempInven, nTempInvenCount);
|
|
if (nBlank < 0) {
|
|
return false;
|
|
}
|
|
|
|
return(__SetBlankInventorySlot(pTempInven, Item, nBlank));
|
|
}
|
|
|
|
return(__SetOverlapInventorySlot(pTempInven, Item, pItem->nOverlapCount, nBlank));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// desc : 퀘스트 인벤토리의 특정 빈슬롯에 아이템을 세팅 (P.S.> api_quest_CheckQuestInvenForAddItemList 에서 사용됨)
|
|
bool __SetBlankQuestInventorySlot(TQuestItemCnt pTempQuestInven[QUESTINVENTORYMAX], int nItemID, short wCount, int iIndex)
|
|
{
|
|
DN_ASSERT(NULL != pTempQuestInven, "Invalid!");
|
|
DN_ASSERT(0 != nItemID, "Invalid!");
|
|
DN_ASSERT(0 < wCount, "Invalid!");
|
|
DN_ASSERT(-1 < iIndex, "Invalid!");
|
|
|
|
if (pTempQuestInven[iIndex].nItemID != 0) {
|
|
return false;
|
|
}
|
|
|
|
pTempQuestInven[iIndex].Set(nItemID, wCount);
|
|
|
|
return true;
|
|
}
|
|
|
|
// desc : 퀘스트 인벤토리의 빈슬롯들에 아이템을 특정 개수만큼 세팅 (P.S.> api_quest_CheckQuestInvenForAddItemList 에서 사용됨)
|
|
bool __SetBlankQuestInventorySlotCount(TQuestItemCnt pTempQuestInven[QUESTINVENTORYMAX], int nItemID, short wCount, int nOverlapCount, int nCount /* 채울 슬롯개수 */)
|
|
{
|
|
DN_ASSERT(NULL != pTempQuestInven, "Invalid!");
|
|
DN_ASSERT(0 != nItemID, "Invalid!");
|
|
DN_ASSERT(0 < wCount, "Invalid!");
|
|
DN_ASSERT(0 < nOverlapCount, "Invalid!");
|
|
DN_ASSERT(0 < nCount, "Invalid!");
|
|
|
|
// !!! 주의 - 본 함수 호출 전에 체크가 확실히 되었음을 전제하고 세팅하는 부분만 수행
|
|
|
|
int nBundle = wCount / nOverlapCount;
|
|
int nRemain = wCount % nOverlapCount;
|
|
|
|
for (int iIndex = 0 ; QUESTINVENTORYMAX > iIndex ; ++iIndex) {
|
|
if (0 < nBundle) {
|
|
if (pTempQuestInven[iIndex].nItemID == 0) {
|
|
pTempQuestInven[iIndex].Set(nItemID, nOverlapCount);
|
|
--nBundle;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (0 < nRemain) {
|
|
if (pTempQuestInven[iIndex].nItemID == nItemID &&
|
|
nOverlapCount >= pTempQuestInven[iIndex].wCount + nRemain
|
|
)
|
|
{
|
|
pTempQuestInven[iIndex].wCount += nRemain;
|
|
nRemain = 0;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (0 < nBundle) {
|
|
return false;
|
|
}
|
|
if (0 < nRemain) {
|
|
for (int iIndex = 0 ; QUESTINVENTORYMAX > iIndex ; ++iIndex) {
|
|
if (pTempQuestInven[iIndex].nItemID == 0) {
|
|
pTempQuestInven[iIndex].Set(nItemID, nRemain);
|
|
nRemain = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (0 < nRemain) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// desc : 퀘스트 인벤토리의 특정 슬롯에 아이템을 중첩 세팅 (P.S.> api_quest_CheckQuestInvenForAddItemList 에서 사용됨)
|
|
bool __SetOverlapQuestInventorySlot(TQuestItemCnt pTempQuestInven[QUESTINVENTORYMAX], int nItemID, short wCount, int nOverlapCount, int iIndex)
|
|
{
|
|
DN_ASSERT(NULL != pTempQuestInven, "Invalid!");
|
|
DN_ASSERT(0 != nItemID, "Invalid!");
|
|
DN_ASSERT(0 < wCount, "Invalid!");
|
|
DN_ASSERT(0 < nOverlapCount, "Invalid!");
|
|
DN_ASSERT(-1 < iIndex, "Invalid!");
|
|
|
|
if (pTempQuestInven[iIndex].nItemID != nItemID ||
|
|
nOverlapCount < pTempQuestInven[iIndex].wCount + wCount
|
|
)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
pTempQuestInven[iIndex].wCount += wCount;
|
|
|
|
return true;
|
|
}
|
|
|
|
// desc : 퀘스트 인벤토리에 빈슬롯이 몇 개나 있는지 개수 찾기 (P.S.> api_quest_CheckQuestInvenForAddItemList 에서 사용됨)
|
|
int __FindBlankQuestInventorySlotCount(TQuestItemCnt pTempQuestInven[QUESTINVENTORYMAX])
|
|
{
|
|
DN_ASSERT(NULL != pTempQuestInven, "Invalid!");
|
|
|
|
int nCount = 0;
|
|
for (int iIndex = 0 ; QUESTINVENTORYMAX > iIndex ; ++iIndex) {
|
|
if (pTempQuestInven[iIndex].nItemID == 0) {
|
|
++nCount;
|
|
}
|
|
}
|
|
|
|
return nCount;
|
|
}
|
|
|
|
// desc : 퀘스트 인벤토리에 빈슬롯 찾기 (P.S.> api_quest_CheckQuestInvenForAddItemList 에서 사용됨)
|
|
int __FindBlankQuestInventorySlot(TQuestItemCnt pTempQuestInven[QUESTINVENTORYMAX])
|
|
{
|
|
DN_ASSERT(NULL != pTempQuestInven, "Invalid!");
|
|
|
|
for (int iIndex = 0 ; QUESTINVENTORYMAX > iIndex ; ++iIndex) {
|
|
if (pTempQuestInven[iIndex].nItemID == 0) {
|
|
return iIndex;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// desc : 퀘스트 인벤토리에 셀 수 있는 아이템 중 남은 공간에 wCount 넣을 수 있는 Index 찾기 (P.S.> api_quest_CheckQuestInvenForAddItemList 에서 사용됨)
|
|
int __FindOverlapQuestInventorySlot(TQuestItemCnt pTempQuestInven[QUESTINVENTORYMAX], int nItemID, short wCount)
|
|
{
|
|
DN_ASSERT(NULL != pTempQuestInven, "Invalid!");
|
|
|
|
if ((nItemID <= 0) || (wCount <= 0)) DN_RETURN(-1);
|
|
|
|
bool boFlag = false;
|
|
TItemData *pQuestItem = NULL;
|
|
for (int iIndex = 0 ; QUESTINVENTORYMAX > iIndex ; ++iIndex) {
|
|
if (pTempQuestInven[iIndex].nItemID == 0) continue; // 빈칸이면 패스
|
|
|
|
pQuestItem = g_pDataManager->GetItemData(pTempQuestInven[iIndex].nItemID);
|
|
if (!pQuestItem) continue;
|
|
|
|
if (pQuestItem->nOverlapCount == 1) continue; // 겹치지 않으면 패스
|
|
if (pTempQuestInven[iIndex].nItemID != nItemID) continue; // 같은 아이템이 아니다
|
|
|
|
if (pQuestItem->nOverlapCount >= pTempQuestInven[iIndex].wCount + wCount){
|
|
return iIndex;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// desc : 퀘스트 인벤토리에 아이템을 넣을 수 있는 공간이 충분한지 검사 (P.S.> api_quest_CheckQuestInvenForAddItemList 에서 사용됨)
|
|
bool __IsValidSpaceQuestInventorySlotAndSet(TQuestItemCnt pTempQuestInven[QUESTINVENTORYMAX], int nItemID, short wCount)
|
|
{
|
|
DN_ASSERT(NULL != pTempQuestInven, "Invalid!");
|
|
|
|
if ((nItemID <= 0) || (wCount <= 0)) DN_RETURN(false);
|
|
|
|
TItemData *pItem = g_pDataManager->GetItemData(nItemID);
|
|
if (!pItem) return false;
|
|
|
|
if (ITEMTYPE_QUEST != pItem->nType) {
|
|
return false;
|
|
}
|
|
|
|
int nCount = 0;
|
|
if (pItem->nOverlapCount == 1){ // 겹치지 않는 아이템
|
|
nCount = __FindBlankQuestInventorySlotCount(pTempQuestInven);
|
|
if (wCount > nCount) {
|
|
// 빈슬롯이랑 비교하기
|
|
return false;
|
|
}
|
|
|
|
return(__SetBlankQuestInventorySlotCount(pTempQuestInven, nItemID, wCount, 1, nCount));
|
|
}
|
|
else { // 겹치는 아이템
|
|
int nRemain = 0, nBlank = 0, nBundle = 0;
|
|
|
|
int nCount = __FindBlankQuestInventorySlotCount(pTempQuestInven); // 빈 슬롯개수
|
|
|
|
if (pItem->nOverlapCount >= wCount){
|
|
nRemain = wCount;
|
|
}
|
|
else {
|
|
nBundle = wCount / pItem->nOverlapCount;
|
|
nRemain = wCount % pItem->nOverlapCount;
|
|
|
|
if (nBundle > nCount) return false; // 공간부족
|
|
}
|
|
|
|
if (nRemain > 0){
|
|
nBlank = __FindOverlapQuestInventorySlot(pTempQuestInven, nItemID, nRemain); // 짜투리가 들어갈 공간이 있는지
|
|
if (nBlank < 0){ // 짜투리 공간은 없다
|
|
if ((nBundle + 1) > nCount) return false; // 한칸의 여유가 더 있는지...
|
|
}
|
|
}
|
|
|
|
return(__SetBlankQuestInventorySlotCount(pTempQuestInven, nItemID, wCount, pItem->nOverlapCount, nCount));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
int CheckInvenForQuestReward(CDNUserBase* pUser, const TQuestReward& QuestReward, const bool bSelectedArray[])
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
const CDNUserItem* pUserItem = pUser->GetItem();
|
|
if (!pUserItem)
|
|
return -2;
|
|
|
|
TInvenItemCnt TempInven[INVENTORYMAX];
|
|
::memset(TempInven, 0, sizeof(TempInven));
|
|
#if defined(PRE_PERIOD_INVENTORY)
|
|
for (int i = 0; i < INVENTORYTOTALMAX; i++)
|
|
{
|
|
if (i == pUserItem->GetInventoryCount()){
|
|
if (pUserItem->IsEnablePeriodInventory())
|
|
i = INVENTORYMAX;
|
|
else
|
|
break;
|
|
}
|
|
#else // #if defined(PRE_PERIOD_INVENTORY)
|
|
for (int i = 0 ; i < INVENTORYMAX; ++i)
|
|
{
|
|
#endif // #if defined(PRE_PERIOD_INVENTORY)
|
|
const TItem* pItem = pUserItem->GetInventory(i);
|
|
if (pItem)
|
|
TempInven[i].Set(pItem->nItemID, pItem->wCount, pItem->bSoulbound, pItem->cSealCount);
|
|
}
|
|
|
|
//만약 빌리지, 게임 둘다 아니면 컴파일 에러.
|
|
#if defined (_VILLAGESERVER)
|
|
UINT nUserObjectID = static_cast<CDNUserSession*>(pUser)->GetObjectID();
|
|
#endif
|
|
|
|
#if defined (_GAMESERVER)
|
|
UINT nUserObjectID = static_cast<CDNUserSession*>(pUser)->GetSessionID();
|
|
#endif
|
|
|
|
bool bSelectedItems[QUESTREWARD_INVENTORYITEMMAX];
|
|
CopyMemory(bSelectedItems, bSelectedArray, sizeof(bSelectedItems));
|
|
if (QuestReward.cType == 1) // 전체 보상이면 아이템을 전부 선택한것으로 취급. (전체 보상과 선택 보상 로직 통일.)
|
|
{
|
|
for (int i = 0; i < QUESTREWARD_INVENTORYITEMMAX; ++i)
|
|
bSelectedItems[i] = true;
|
|
}
|
|
|
|
for (int i = 0; i < QUESTREWARD_INVENTORYITEMMAX; ++i)
|
|
{
|
|
if(!bSelectedItems[i])
|
|
continue;
|
|
|
|
if (QuestReward.ItemArray[i].nItemID <= 0 || QuestReward.ItemArray[i].nItemCount <= 0)
|
|
continue;
|
|
|
|
TItem Item;
|
|
if (!CDNUserItem::MakeItemStruct(QuestReward.ItemArray[i].nItemID, Item))
|
|
return -3;
|
|
|
|
Item.wCount = QuestReward.ItemArray[i].nItemCount;
|
|
if (!__IsValidSpaceInventorySlotAndSet(TempInven, pUserItem->GetInventoryCount(), Item))
|
|
return -4;
|
|
}
|
|
|
|
for (int i = 0; i < MAX_QUEST_LEVEL_CAP_REWARD; ++i)
|
|
{
|
|
if (QuestReward.LevelCapItemArray[i].nItemID <= 0 || QuestReward.LevelCapItemArray[i].nItemCount <= 0)
|
|
continue;
|
|
|
|
TItem Item;
|
|
if (!CDNUserItem::MakeItemStruct(QuestReward.LevelCapItemArray[i].nItemID, Item))
|
|
return -3;
|
|
|
|
Item.wCount = QuestReward.LevelCapItemArray[i].nItemCount;
|
|
if (!__IsValidSpaceInventorySlotAndSet(TempInven, pUserItem->GetInventoryCount(), Item))
|
|
return -4;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
void api_npc_NextTalk(CDNUserBase* pUser, UINT nNpcObjectID, const char* szTalkIndex, const char* szTargetFile)
|
|
{
|
|
if (!pUser)
|
|
return;
|
|
|
|
WCHAR wszTalkIndex[512] = {0,};
|
|
WCHAR wszTargetFile[512] = {0,};
|
|
|
|
ZeroMemory(&wszTalkIndex, sizeof(WCHAR)*512);
|
|
MultiByteToWideChar(CP_ACP, 0, szTalkIndex, -1, wszTalkIndex, 512 );
|
|
|
|
ZeroMemory(&wszTargetFile, sizeof(WCHAR)*512);
|
|
MultiByteToWideChar(CP_ACP, 0, szTargetFile, -1, wszTargetFile, 512 );
|
|
|
|
// 다음 대사문단을 세팅해놓는다.
|
|
// 유저한테 온 패킷이 이 대사 목록중에 없으면 뭔가가 조작된거임..
|
|
TALK_PARAGRAPH& para = pUser->GetLastTalkParagraph();
|
|
bool bResult = g_pDataManager->GetTalkParagraph(std::wstring(wszTalkIndex), std::wstring(wszTargetFile), para);
|
|
if ( bResult == false )
|
|
{
|
|
#if defined (_VILLAGESERVER)
|
|
if (!g_pDataManager->CheckTalkAnswer(std::wstring(wszTalkIndex), std::wstring(wszTargetFile))) { // 컷신 등은 talk_paragraph 없이 talk_answer 만 존재하는 경우가 있으며 이것은 유효함
|
|
pUser->SendNextTalkError();
|
|
}
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
pUser->SetCalledNpcResponse(true, true);
|
|
|
|
std::vector<TalkParam>& talkParamList = pUser->GetTalkParamList();
|
|
pUser->NextTalk(nNpcObjectID, wszTalkIndex, wszTargetFile, talkParamList );
|
|
talkParamList.clear();
|
|
}
|
|
|
|
void api_npc_NextScript(CDNUserBase* pUser, CDnNpc* pNpc, UINT nNpcObjectID, const char* szTalkIndex, const char* szTargetFile)
|
|
{
|
|
WCHAR wszTalkIndex[512];
|
|
WCHAR wszTargetFile[512];
|
|
|
|
ZeroMemory(&wszTalkIndex, sizeof(WCHAR)*512);
|
|
MultiByteToWideChar(CP_ACP, 0, szTalkIndex, -1, wszTalkIndex, 512 );
|
|
|
|
ZeroMemory(&wszTargetFile, sizeof(WCHAR)*512);
|
|
MultiByteToWideChar(CP_ACP, 0, szTargetFile, -1, wszTargetFile, 512 );
|
|
|
|
// 다음 대사문단을 세팅해놓는다.
|
|
// 유저한테 온 패킷이 이 대사 목록중에 없으면 뭔가가 조작된거임..
|
|
TALK_PARAGRAPH& para = pUser->GetLastTalkParagraph();
|
|
bool bResult = g_pDataManager->GetTalkParagraph(std::wstring(wszTalkIndex), std::wstring(wszTargetFile), para);
|
|
if ( bResult == false ) return;
|
|
|
|
bool& bSkipCheck = pUser->GetSkipParagraphCheck();
|
|
bSkipCheck = true;
|
|
|
|
pUser->SetCalledNpcResponse(true, true);
|
|
|
|
pNpc->Talk(pUser, nNpcObjectID, std::wstring(wszTalkIndex), std::wstring(wszTargetFile) );
|
|
}
|
|
|
|
int api_npc_SetParamString(CDNUserBase* pUser, const char* szParamKey, int nParamID)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
std::vector<TalkParam>& talkParamList = pUser->GetTalkParamList();
|
|
|
|
if ( talkParamList.size() > 10 ) return -2;
|
|
std::wstring wszParam;
|
|
ToWideString(std::string(szParamKey), wszParam);
|
|
|
|
TalkParam talkparam;
|
|
ZeroMemory(&talkparam, sizeof(TalkParam));
|
|
talkparam.cType = TalkParam::STRING;
|
|
_wcscpy(talkparam.wszKey, _countof(talkparam.wszKey), wszParam.c_str(), (int)wcslen(wszParam.c_str()));
|
|
talkparam.nValue = nParamID;
|
|
|
|
talkParamList.push_back(talkparam);
|
|
return 1;
|
|
}
|
|
|
|
int api_npc_SetParamInt(CDNUserBase* pUser, const char* szParamKey, int nValue)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
std::vector<TalkParam>& talkParamList = pUser->GetTalkParamList();
|
|
|
|
if ( talkParamList.size() > 10 ) return -2;
|
|
std::wstring wszParam;
|
|
ToWideString(std::string(szParamKey), wszParam);
|
|
|
|
TalkParam talkparam;
|
|
ZeroMemory(&talkparam, sizeof(TalkParam));
|
|
talkparam.cType = TalkParam::INT;
|
|
_wcscpy(talkparam.wszKey, _countof(talkparam.wszKey), wszParam.c_str(), (int)wcslen(wszParam.c_str()));
|
|
talkparam.nValue = nValue;
|
|
|
|
talkParamList.push_back(talkparam);
|
|
return 1;
|
|
}
|
|
|
|
void api_log_AddLog(const char* szLog)
|
|
{
|
|
#if !defined(_FINAL_BUILD)
|
|
WCHAR wszMsg[512];
|
|
|
|
ZeroMemory(&wszMsg, sizeof(WCHAR)*512);
|
|
MultiByteToWideChar(CP_ACP, 0, szLog, -1, wszMsg, 512 );
|
|
|
|
g_ScriptLog.Log(LogType::_FILELOG, wszMsg);
|
|
#endif //#if !defined(_FINAL_BUILD)
|
|
}
|
|
|
|
void api_log_UserLog(CDNUserBase* pUser, const char* szLog)
|
|
{
|
|
#if !defined(_FINAL_BUILD)
|
|
if (!pUser)
|
|
return;
|
|
|
|
WCHAR wszMsg[512]={0,};
|
|
|
|
ZeroMemory(&wszMsg, sizeof(WCHAR)*512);
|
|
MultiByteToWideChar(CP_ACP, 0, szLog, -1, wszMsg, 512 );
|
|
|
|
std::wstring wszString;
|
|
wszString = wszMsg;
|
|
static_cast<CDNUserSession*>(pUser)->SendChat(CHATTYPE_NORMAL, (int)wszString.size()*sizeof(WCHAR), L"", (WCHAR*)wszString.c_str());
|
|
#endif //#if !defined(_FINAL_BUILD)
|
|
}
|
|
|
|
/*
|
|
desc : 유저에게 퀘스트 관련 정보를 채팅으로 보내준다.
|
|
param :
|
|
return : void
|
|
*/
|
|
void api_quest_DumpQuest(CDNUserBase* pUser)
|
|
{
|
|
#if !defined(_FINAL_BUILD)
|
|
if (!pUser)
|
|
return;
|
|
|
|
std::vector<TQuest> QuestList;
|
|
pUser->GetQuest()->DumpQuest(QuestList);
|
|
|
|
for ( size_t i = 0 ; i < QuestList.size() ; i++ )
|
|
{
|
|
TQuest& quest = QuestList[i];
|
|
|
|
std::wstring wszString;
|
|
wszString = FormatW( L"[Slot:%d] QID:%d Type:%d QStep:%d JStep:%d Marking:%d\n", i,
|
|
(int)quest.nQuestID, g_pQuestManager->GetQuestType(quest.nQuestID), (int)quest.nQuestStep, (int)quest.cQuestJournal,
|
|
(!quest.nQuestID)?(0):(pUser->GetQuest()->IsClearQuest(quest.nQuestID))
|
|
);
|
|
|
|
static_cast<CDNUserSession*>(pUser)->SendChat(CHATTYPE_NORMAL, (int)wszString.size()*sizeof(WCHAR), L"", (WCHAR*)wszString.c_str());
|
|
}
|
|
#endif //#if !defined(_FINAL_BUILD)
|
|
}
|
|
|
|
int api_quest_AddHuntingQuest(CDNUserBase* pUser, int nQuestID, int nQuestStep, int nJournalStep, int nCountingSlot, int nCountingType, int nCountingIndex, int nTargetCnt)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#if defined(_CH)
|
|
if (pUser->GetFCMState() != FCMSTATE_NONE){
|
|
pUser->SendQuestResult(ERROR_QUEST_FCM);
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
return pUser->GetQuest()->AddHuntingQuest(nQuestID, nQuestStep, nJournalStep, nCountingSlot, nCountingType, nCountingIndex, nTargetCnt);
|
|
}
|
|
|
|
// nQuestType : 사용하지 않는 매개변수임.
|
|
int api_quest_AddQuest(CDNUserBase* pUser, int nQuestID, int nQuestType)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#if defined(_CH)
|
|
if (pUser->GetFCMState() != FCMSTATE_NONE){
|
|
pUser->SendQuestResult(ERROR_QUEST_FCM);
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
return pUser->GetQuest()->AddQuest(nQuestID);
|
|
}
|
|
|
|
int api_quest_CompleteQuest(CDNUserBase* pUser, int nQuestID, bool bDelPlayList)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#if defined(_CH)
|
|
if (pUser->GetFCMState() != FCMSTATE_NONE){
|
|
pUser->SendQuestResult(ERROR_QUEST_FCM);
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
// 퀘스트 완료
|
|
int nReturn = pUser->GetQuest()->RewardAfterCompletingQuest(nQuestID, bDelPlayList);
|
|
|
|
// 보상관련 변수 초기화
|
|
pUser->GetQuest()->ResetRewardFlag();
|
|
|
|
return nReturn;
|
|
}
|
|
|
|
int api_quest_IsMarkingCompleteQuest(CDNUserBase* pUser, int nQuestID)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
return (pUser->GetQuest()->IsClearQuest(nQuestID)) ? 1 : 0;
|
|
}
|
|
|
|
int api_quest_UserHasQuest(CDNUserBase* pUser, int nQuestID)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
return pUser->GetQuest()->HasQuest(nQuestID);
|
|
}
|
|
|
|
int api_quest_GetPlayingQuestCnt(CDNUserBase* pUser)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
return pUser->GetQuest()->GetPlayingQuestCount();
|
|
}
|
|
|
|
int api_npc_GetNpcIndex(CDnNpc* pNpc)
|
|
{
|
|
if (!pNpc)
|
|
return -2;
|
|
|
|
return pNpc->GetNpcData()->nNpcID;
|
|
}
|
|
|
|
int api_quest_SetQuestStepAndJournalStep(CDNUserBase* pUser, int nQuestID, short nQuestStep, int nJournalStep)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#if defined(_CH)
|
|
if (pUser->GetFCMState() != FCMSTATE_NONE){
|
|
pUser->SendQuestResult(ERROR_QUEST_FCM);
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
if ( nJournalStep < 0 || nJournalStep > 255 )
|
|
return -3;
|
|
|
|
return pUser->GetQuest()->SetQuestStepAndJournalStep(nQuestID, nQuestStep, nJournalStep, true);
|
|
}
|
|
|
|
int api_quest_SetQuestStep(CDNUserBase* pUser, int nQuestID, short nQuestStep)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#if defined(_CH)
|
|
if (pUser->GetFCMState() != FCMSTATE_NONE){
|
|
pUser->SendQuestResult(ERROR_QUEST_FCM);
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
return pUser->GetQuest()->SetQuestStep(nQuestID, nQuestStep);
|
|
}
|
|
|
|
int api_quest_GetQuestStep(CDNUserBase* pUser, int nQuestID)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
return pUser->GetQuest()->GetQuestStep(nQuestID);
|
|
}
|
|
|
|
int api_quest_SetJournalStep(CDNUserBase* pUser, int nQuestID, int nJournalStep)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#if defined(_CH)
|
|
if (pUser->GetFCMState() != FCMSTATE_NONE){
|
|
pUser->SendQuestResult(ERROR_QUEST_FCM);
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
if ( nJournalStep < 0 || nJournalStep > 255 )
|
|
return -3;
|
|
|
|
return pUser->GetQuest()->SetJournalStep(nQuestID, nJournalStep);
|
|
}
|
|
|
|
int api_quest_GetJournalStep(CDNUserBase* pUser, int nQuestID)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
return pUser->GetQuest()->GetJournalStep(nQuestID);
|
|
}
|
|
|
|
int api_quest_SetQuestMemo(CDNUserBase* pUser, int nQuestID, char nMemoIndex, int iVal)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#if defined(_CH)
|
|
if (pUser->GetFCMState() != FCMSTATE_NONE){
|
|
pUser->SendQuestResult(ERROR_QUEST_FCM);
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
if (QUESTMEMOREWARDCHECK == nMemoIndex) {
|
|
// 퀘스트 보상 무한지급을 방지하기 위하여 할당받은 인덱스는 사용할 수 없음
|
|
DN_RETURN(-3);
|
|
}
|
|
|
|
if (!CHECK_RANGE(nMemoIndex, 1, QUESTMEMOMAX)) {
|
|
// 퀘스트 메모 인덱스 범위를 벗어남 (1~10)
|
|
DN_RETURN(-3);
|
|
}
|
|
|
|
return pUser->GetQuest()->SetQuestMemo(nQuestID, nMemoIndex-1, iVal);
|
|
}
|
|
|
|
int api_quest_GetQuestMemo(CDNUserBase* pUser, int nQuestID, char nMemoIndex)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
if (!CHECK_RANGE(nMemoIndex, 1, QUESTMEMOMAX)) {
|
|
// 퀘스트 메모 인덱스 범위를 벗어남 (1~10)
|
|
DN_RETURN(-3);
|
|
}
|
|
|
|
return pUser->GetQuest()->GetQuestMemo(nQuestID, nMemoIndex-1);
|
|
}
|
|
|
|
int api_quest_SetCountingInfo(CDNUserBase* pUser, int nQuestID, int nSlot, int nCountingType, int nCountingIndex, int nTargetCnt)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
return pUser->GetQuest()->SetCountingInfo(nQuestID, nSlot, nCountingType, nCountingIndex, nTargetCnt);
|
|
}
|
|
|
|
int api_quest_ClearCountingInfo(CDNUserBase* pUser, int nQuestID)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
return pUser->GetQuest()->ClearCountingInfo(nQuestID);
|
|
}
|
|
|
|
int api_quest_IsAllCompleteCounting(CDNUserBase* pUser, int nQuestID)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
return pUser->GetQuest()->IsAllCompleteCounting(nQuestID);
|
|
}
|
|
|
|
int api_user_CheckInvenForAddItem(CDNUserBase* pUser, int nItemIndex, int nItemCnt)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
CDNUserItem* pUserItem = pUser->GetItem();
|
|
if (!pUserItem) {
|
|
return -2;
|
|
}
|
|
|
|
TItem ResultItem;
|
|
if( CDNUserItem::MakeItemStruct( nItemIndex, ResultItem ) == false )
|
|
return -2;
|
|
// 일단은 임시로 빈공간만 확인한다.
|
|
// 인벤에 빈공간이 없으면
|
|
if (!pUserItem->IsValidSpaceInventorySlot(nItemIndex, nItemCnt, ResultItem.bSoulbound, ResultItem.cSealCount, ResultItem.bEternity))
|
|
{
|
|
#if defined (_GAMESERVER)
|
|
pUser->SendQuestResult(ERROR_ITEM_INVENTORY_NOTENOUGH);
|
|
#endif
|
|
return -3;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int api_user_CheckInvenForAddItemList(CDNUserBase* pUser, lua_tinker::table ItemTable)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
CDNUserItem* pUserItem = pUser->GetItem();
|
|
if (!pUserItem) {
|
|
return -2;
|
|
}
|
|
|
|
TInvenItemCnt TempInven[INVENTORYMAX];
|
|
{
|
|
// 임시 인벤토리에 현재 인벤토리의 아이템 개수 정보들을 복사
|
|
|
|
::memset(TempInven, 0, sizeof(TempInven));
|
|
|
|
for (int iIndex = 0 ; INVENTORYMAX > iIndex ; ++iIndex)
|
|
{
|
|
const TItem* pItem = pUserItem->GetInventory(iIndex);
|
|
if (pItem)
|
|
{
|
|
TempInven[iIndex].Set(pItem->nItemID, pItem->wCount, pItem->bSoulbound, pItem->cSealCount );
|
|
}
|
|
else
|
|
{
|
|
TempInven[iIndex].Reset();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (0 >= ItemTable.getSize())
|
|
{
|
|
// 아이템 테이블에 아무값도 없음 ?
|
|
DN_RETURN(false);
|
|
}
|
|
|
|
for (int iIndex = 1 ; ItemTable.getSize() >= iIndex ; ++iIndex)
|
|
{
|
|
lua_tinker::table pTable = ItemTable.get<lua_tinker::table>(iIndex);
|
|
if (0 >= pTable.getSize())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
TItem Item;
|
|
if( CDNUserItem::MakeItemStruct( pTable.get<int>(1), Item ) == false )
|
|
return -2;
|
|
Item.wCount = pTable.get<int>(2);
|
|
|
|
bool bResult = __IsValidSpaceInventorySlotAndSet(TempInven, pUserItem->GetInventoryCount(), Item ); // RandomSeed 는 어떻게 ?
|
|
if (!bResult)
|
|
{
|
|
#if defined (_GAMESERVER)
|
|
pUser->SendQuestResult(ERROR_ITEM_INVENTORY_NOTENOUGH);
|
|
#endif
|
|
return -3;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int api_user_AddItem(CDNUserBase* pUser, int nItemIndex, int nItemCnt, int nQuestID)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#if defined(_CH)
|
|
if (pUser->GetFCMState() != FCMSTATE_NONE){
|
|
pUser->SendQuestResult(ERROR_QUEST_FCM);
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
CDNUserItem* pUserItem = pUser->GetItem();
|
|
if ( !pUserItem )
|
|
return -2;
|
|
|
|
#if defined (_VILLAGESERVER)
|
|
int nResult = api_user_CheckInvenForAddItem(pUser, nItemIndex, nItemCnt);
|
|
|
|
if ( nResult < 0 )
|
|
return nResult;
|
|
|
|
bool bResult = pUserItem->AddInventoryByQuest(nItemIndex, nItemCnt, nQuestID, 0); // 아이템에 따라서 randomseed 를 어떻게 넣을껀지 결정해주시길!
|
|
|
|
#ifndef _FINAL_BUILD
|
|
if ( bResult )
|
|
{
|
|
std::wstring wszMsg;
|
|
wszMsg = FormatW( L"아이템 지급 : id %d count : %d" , nItemIndex, nItemCnt );
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszMsg.size()*sizeof(WCHAR), L"", (WCHAR*)wszMsg.c_str());
|
|
}
|
|
else
|
|
{
|
|
std::wstring wszMsg;
|
|
wszMsg = FormatW( L"아이템 지급 실패 : id %d count : %d" , nItemIndex, nItemCnt );
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszMsg.size()*sizeof(WCHAR), L"", (WCHAR*)wszMsg.c_str());
|
|
}
|
|
#endif //#ifndef _FINAL_BUILD
|
|
#endif //#if defined (_VILLAGESERVER)
|
|
|
|
#if defined (_GAMESERVER)
|
|
TItem ResultItem;
|
|
if( CDNUserItem::MakeItemStruct(nItemIndex, ResultItem) == false )
|
|
return -2;
|
|
// 일단은 임시로 빈공간만 확인한다.
|
|
// 인벤에 빈공간이 없으면
|
|
if ( !pUserItem->IsValidSpaceInventorySlot(nItemIndex, nItemCnt, ResultItem.bSoulbound, ResultItem.cSealCount, ResultItem.bEternity ) )
|
|
{
|
|
return -3;
|
|
}
|
|
|
|
bool bResult = pUserItem->AddInventoryByQuest(nItemIndex, nItemCnt, nQuestID, 0); // 아이템에 따라서 randomseed 를 어떻게 넣을껀지 결정해주시길!
|
|
|
|
#if defined( PRE_ENABLE_QUESTCHATLOG )
|
|
if ( bResult )
|
|
{
|
|
// 임시로 실제로 주진 않고 유저 채팅창에만 찍어준다.
|
|
std::wstring wszMsg;
|
|
wszMsg = FormatW( L"아이템 지급 : id %d count : %d" , nItemIndex, nItemCnt );
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszMsg.size()*sizeof(WCHAR), L"", (WCHAR*)wszMsg.c_str());
|
|
}
|
|
else
|
|
{
|
|
// 임시로 실제로 주진 않고 유저 채팅창에만 찍어준다.
|
|
std::wstring wszMsg;
|
|
wszMsg = FormatW( L"아이템 지급 실패 : id %d count : %d" , nItemIndex, nItemCnt );
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszMsg.size()*sizeof(WCHAR), L"", (WCHAR*)wszMsg.c_str());
|
|
}
|
|
#endif // #if defined( PRE_ENABLE_QUESTCHATLOG )
|
|
#endif //#if defined (_GAMESERVER)
|
|
|
|
return 1;
|
|
}
|
|
|
|
int api_user_DelItem(CDNUserBase* pUser, int nItemIndex, int nItemCnt, int nQuestID)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#if defined(_CH)
|
|
if (pUser->GetFCMState() != FCMSTATE_NONE){
|
|
pUser->SendQuestResult(ERROR_QUEST_FCM);
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
CDNUserItem* pUserItem = pUser->GetItem();
|
|
if ( !pUserItem )
|
|
return -2;
|
|
|
|
int nCount = pUserItem->GetInventoryItemCount(nItemIndex);
|
|
if ( nCount < nItemCnt )
|
|
{
|
|
return -3;
|
|
}
|
|
|
|
bool bResult = pUserItem->DeleteInventoryByQuest(nItemIndex, nItemCnt, nQuestID);
|
|
|
|
#if defined (_VILLAGESERVER)
|
|
#ifndef _FINAL_BUILD
|
|
if ( bResult )
|
|
{
|
|
std::wstring wszMsg;
|
|
wszMsg = FormatW( L"아이템 제거 : id %d count : %d" , nItemIndex, nItemCnt );
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszMsg.size()*sizeof(WCHAR), L"", (WCHAR*)wszMsg.c_str());
|
|
}
|
|
else
|
|
{
|
|
std::wstring wszMsg;
|
|
wszMsg = FormatW( L"아이템 제거 실패 : id %d count : %d" , nItemIndex, nItemCnt );
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszMsg.size()*sizeof(WCHAR), L"", (WCHAR*)wszMsg.c_str());
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#if defined (_GAMESERVER)
|
|
#if defined (PRE_ENABLE_QUESTCHATLOG)
|
|
if ( bResult )
|
|
{
|
|
std::wstring wszMsg;
|
|
wszMsg = FormatW( L"아이템 제거 : id %d count : %d" , nItemIndex, nItemCnt );
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszMsg.size()*sizeof(WCHAR), L"", (WCHAR*)wszMsg.c_str());
|
|
}
|
|
else
|
|
{
|
|
std::wstring wszMsg;
|
|
wszMsg = FormatW( L"아이템 제거 실패 : id %d count : %d" , nItemIndex, nItemCnt );
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszMsg.size()*sizeof(WCHAR), L"", (WCHAR*)wszMsg.c_str());
|
|
}
|
|
#endif
|
|
#endif
|
|
return 1;
|
|
}
|
|
|
|
int api_user_AllDelItem(CDNUserBase* pUser, int nItemIndex)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#if defined(_CH)
|
|
if (pUser->GetFCMState() != FCMSTATE_NONE){
|
|
pUser->SendQuestResult(ERROR_QUEST_FCM);
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
CDNUserItem* pUserItem = pUser->GetItem();
|
|
if ( !pUserItem )
|
|
return -2;
|
|
|
|
int nCount = pUserItem->GetInventoryItemCount(nItemIndex);
|
|
|
|
bool bResult = pUserItem->DeleteInventoryByQuest(nItemIndex, nCount, 0);
|
|
|
|
#if defined (_VILLAGESERVER)
|
|
#ifndef _FINAL_BUILD
|
|
if ( bResult )
|
|
{
|
|
std::wstring wszMsg;
|
|
wszMsg = FormatW( L"아이템 제거 : id %d count : %d" , nItemIndex, nCount );
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszMsg.size()*sizeof(WCHAR), L"", (WCHAR*)wszMsg.c_str());
|
|
}
|
|
else
|
|
{
|
|
std::wstring wszMsg;
|
|
wszMsg = FormatW( L"아이템 제거 실패 : id %d count : %d" , nItemIndex, nCount );
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszMsg.size()*sizeof(WCHAR), L"", (WCHAR*)wszMsg.c_str());
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#if defined (_GAMESERVER)
|
|
#if defined (PRE_ENABLE_QUESTCHATLOG)
|
|
if ( bResult )
|
|
{
|
|
std::wstring wszMsg;
|
|
wszMsg = FormatW( L"아이템 제거 : id %d count : %d" , nItemIndex, nItemCnt );
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszMsg.size()*sizeof(WCHAR), L"", (WCHAR*)wszMsg.c_str());
|
|
}
|
|
else
|
|
{
|
|
std::wstring wszMsg;
|
|
wszMsg = FormatW( L"아이템 제거 실패 : id %d count : %d" , nItemIndex, nItemCnt );
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszMsg.size()*sizeof(WCHAR), L"", (WCHAR*)wszMsg.c_str());
|
|
}
|
|
#endif
|
|
#endif
|
|
return 1;
|
|
}
|
|
|
|
int api_user_HasItem(CDNUserBase* pUser, int nItemIndex, int nItemCnt)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
CDNUserItem* pUserItem = pUser->GetItem();
|
|
if ( !pUserItem )
|
|
return -2;
|
|
|
|
int nCount = pUserItem->GetInventoryItemCount(nItemIndex);
|
|
if (nCount < nItemCnt)
|
|
{
|
|
return -3;
|
|
}
|
|
|
|
return nCount;
|
|
}
|
|
|
|
int api_user_GetUserClassID(CDNUserBase* pUser)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
return int(pUser->GetClassID());
|
|
}
|
|
|
|
int api_user_GetUserJobID(CDNUserBase* pUser)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
return pUser->GetUserJob();
|
|
}
|
|
|
|
int api_user_GetUserLevel(CDNUserBase* pUser)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
return int(pUser->GetLevel());
|
|
}
|
|
|
|
int api_user_GetUserInvenBlankCount(CDNUserBase* pUser)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
CDNUserItem* pUserItem = pUser->GetItem();
|
|
if ( !pUserItem )
|
|
return -2;
|
|
|
|
return pUserItem->FindBlankInventorySlotCount();
|
|
}
|
|
|
|
int api_quest_GetUserQuestInvenBlankCount(CDNUserBase* pUser)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
CDNUserItem* pUserItem = pUser->GetItem();
|
|
if ( !pUserItem )
|
|
return -2;
|
|
|
|
return pUserItem->FindBlankQuestInventorySlotCount();
|
|
}
|
|
|
|
int api_user_PlayCutScene(CDNUserBase* pUser, UINT nNpcObjectID, int nCutSceneTableID, bool bIgnoreFadeIn)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#ifndef _FINAL_BUILD
|
|
DNTableFileFormat* pSox = GetDNTable( CDnTableDB::TCUTSCENE );
|
|
if( pSox->IsExistItem( nCutSceneTableID ) == false ) {
|
|
std::wstring wszLog;
|
|
wszLog = FormatW( L"동영상 플레이 파일 인덱스가 잘못되었습니다. : %d", nCutSceneTableID);
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszLog.size()*sizeof(WCHAR), L"", (WCHAR*)wszLog.c_str());
|
|
return -1;
|
|
}
|
|
std::string szFileName = pSox->GetFieldFromLablePtr( nCutSceneTableID, "_FileName" )->GetString();
|
|
WCHAR wszMsg[512];
|
|
|
|
ZeroMemory(&wszMsg, sizeof(WCHAR)*512);
|
|
MultiByteToWideChar(CP_ACP, 0, szFileName.c_str(), -1, wszMsg, 512 );
|
|
|
|
std::wstring wszLog;
|
|
wszLog = FormatW( L"동영상 플레이 %s : ", wszMsg);
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszLog.size()*sizeof(WCHAR), L"", (WCHAR*)wszLog.c_str());
|
|
#endif
|
|
|
|
pUser->SendPlayCutScene( nCutSceneTableID,-1, -1, nNpcObjectID, !bIgnoreFadeIn, UINT_MAX );
|
|
pUser->SetCalledNpcResponse(true, false); // 보통 클라이언트에 보내는 UI 개설 요청 이후 대화로 이어지지 않기 때문에 에러가 아닌데도 본의아니게 NPC 응답여부 체크에 걸리게 되므로 대화한 것으로 처리해 줌
|
|
|
|
return 1;
|
|
}
|
|
|
|
int api_ui_OpenWareHouse(CDNUserBase* pUser, int iItemID/*=0*/ )
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#ifndef _FINAL_BUILD
|
|
std::wstring wszLog;
|
|
wszLog = FormatW( L"창고열기");
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszLog.size()*sizeof(WCHAR), L"", (WCHAR*)wszLog.c_str());
|
|
#endif
|
|
|
|
pUser->SendShowWarehouse( iItemID );
|
|
pUser->SetCalledNpcResponse(true, false); // 보통 클라이언트에 보내는 UI 개설 요청 이후 대화로 이어지지 않기 때문에 에러가 아닌데도 본의아니게 NPC 응답여부 체크에 걸리게 되므로 대화한 것으로 처리해 줌
|
|
|
|
return 1;
|
|
}
|
|
|
|
#if defined (PRE_MOD_GAMESERVERSHOP)
|
|
int api_ui_OpenShop(CDNUserBase* pUser, int nShopID, Shop::Type::eCode Type)
|
|
{
|
|
|
|
#ifndef _FINAL_BUILD
|
|
std::wstring wszLog;
|
|
wszLog = FormatW( L"샵열기");
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszLog.size()*sizeof(WCHAR), L"", (WCHAR*)wszLog.c_str());
|
|
#endif
|
|
|
|
TShopData *pShopData = g_pDataManager->GetShopData(nShopID);
|
|
if ( !pShopData )
|
|
{
|
|
if( false == g_pDataManager->IsCombinedShop( nShopID ) )
|
|
return -2;
|
|
}
|
|
|
|
#if defined(PRE_ADD_REMOTE_OPENSHOP)
|
|
pUser->m_bRemoteShopOpen = false;
|
|
#endif // #if defined(PRE_ADD_REMOTE_OPENSHOP)
|
|
pUser->m_nShopID = nShopID;
|
|
pUser->SendShopOpen(nShopID,Type);
|
|
pUser->SetShopType( Type );
|
|
pUser->SetCalledNpcResponse(true, false); // 보통 클라이언트에 보내는 UI 개설 요청 이후 대화로 이어지지 않기 때문에 에러가 아닌데도 본의아니게 NPC 응답여부 체크에 걸리게 되므로 대화한 것으로 처리해 줌
|
|
|
|
return 1;
|
|
}
|
|
|
|
int api_ui_OpenSkillShop(CDNUserBase* pUser)
|
|
{
|
|
#ifndef _FINAL_BUILD
|
|
//std::wstring wszLog;
|
|
//wszLog = FormatW( L"돈주고 언락하는 스킬샵 열기");
|
|
//pUser->SendChat(CHATTYPE_NORMAL, (int)wszLog.size()*sizeof(WCHAR), L"", (WCHAR*)wszLog.c_str());
|
|
#endif
|
|
|
|
pUser->SendSkillShopOpen();
|
|
|
|
//TSkillShopData *pShopData = g_pDataManager->GetSkillShopData(nSkillShopID);
|
|
//if ( !pShopData )
|
|
// return -2;
|
|
//
|
|
//pUser->m_nShopID = nSkillShopID;
|
|
//pUser->SendSkillShopList(pShopData);
|
|
|
|
pUser->SetCalledNpcResponse(true, false); // 보통 클라이언트에 보내는 UI 개설 요청 이후 대화로 이어지지 않기 때문에 에러가 아닌데도 본의아니게 NPC 응답여부 체크에 걸리게 되므로 대화한 것으로 처리해 줌
|
|
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
int api_ui_OpenCompoundEmblem(CDNUserBase* pUser)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#ifndef _FINAL_BUILD
|
|
std::wstring wszLog;
|
|
wszLog = FormatW( L"문장보옥 합성 창열기");
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszLog.size()*sizeof(WCHAR), L"", (WCHAR*)wszLog.c_str());
|
|
#endif
|
|
|
|
pUser->SendOpenCompoundEmblem();
|
|
pUser->SetCalledNpcResponse(true, false); // 보통 클라이언트에 보내는 UI 개설 요청 이후 대화로 이어지지 않기 때문에 에러가 아닌데도 본의아니게 NPC 응답여부 체크에 걸리게 되므로 대화한 것으로 처리해 줌
|
|
|
|
return 1;
|
|
}
|
|
|
|
int api_ui_OpenUpgradeJewel(CDNUserBase* pUser)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#ifndef _FINAL_BUILD
|
|
std::wstring wszLog;
|
|
wszLog = FormatW( L"무인상점 열기");
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszLog.size()*sizeof(WCHAR), L"", (WCHAR*)wszLog.c_str());
|
|
#endif
|
|
|
|
pUser->SendOpenUpdagrageJewel();
|
|
pUser->SetCalledNpcResponse(true, false); // 보통 클라이언트에 보내는 UI 개설 요청 이후 대화로 이어지지 않기 때문에 에러가 아닌데도 본의아니게 NPC 응답여부 체크에 걸리게 되므로 대화한 것으로 처리해 줌
|
|
|
|
return 1;
|
|
}
|
|
|
|
int api_ui_OpenGlyphLift(CDNUserBase* pUser)
|
|
{
|
|
if ( !pUser )
|
|
return -1;
|
|
|
|
#ifndef _FINAL_BUILD
|
|
std::wstring wszLog;
|
|
wszLog = FormatW( L"문장창 열기");
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszLog.size()*sizeof(WCHAR), L"", (WCHAR*)wszLog.c_str());
|
|
#endif
|
|
|
|
pUser->SendOpenGlyphLift();
|
|
pUser->SetCalledNpcResponse(true, false); // 보통 클라이언트에 보내는 UI 개설 요청 이후 대화로 이어지지 않기 때문에 에러가 아닌데도 본의아니게 NPC 응답여부 체크에 걸리게 되므로 대화한 것으로 처리해 줌
|
|
|
|
return 1;
|
|
}
|
|
|
|
int api_ui_OpenMailBox(CDNUserBase* pUser)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#ifndef _FINAL_BUILD
|
|
std::wstring wszLog;
|
|
wszLog = FormatW( L"우편함 열기");
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszLog.size()*sizeof(WCHAR), L"", (WCHAR*)wszLog.c_str());
|
|
#endif
|
|
|
|
pUser->SendOpenMailBox();
|
|
pUser->SetCalledNpcResponse(true, false); // 보통 클라이언트에 보내는 UI 개설 요청 이후 대화로 이어지지 않기 때문에 에러가 아닌데도 본의아니게 NPC 응답여부 체크에 걸리게 되므로 대화한 것으로 처리해 줌
|
|
|
|
return 1;
|
|
}
|
|
|
|
int api_ui_OpenDisjointItem(CDNUserBase* pUser)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#if defined (_VILLAGESERVER)
|
|
#ifndef _FINAL_BUILD
|
|
wstring wszString = FormatW(L"스테이지에서만 사용 가능한 기능입니다.\r\n");
|
|
pUser->SendChat( CHATTYPE_NORMAL, (int)wszString.size()*sizeof(WCHAR), L"", (WCHAR*)wszString.c_str() );
|
|
#endif // _FINAL_BUILD
|
|
#endif
|
|
|
|
#if defined (_GAMESERVER)
|
|
#ifndef _FINAL_BUILD
|
|
std::wstring wszLog;
|
|
wszLog = FormatW( L"분해창 열기");
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszLog.size()*sizeof(WCHAR), L"", (WCHAR*)wszLog.c_str());
|
|
#endif
|
|
#endif
|
|
pUser->SendOpenDisjointItem();
|
|
pUser->SetCalledNpcResponse(true, false); // 보통 클라이언트에 보내는 UI 개설 요청 이후 대화로 이어지지 않기 때문에 에러가 아닌데도 본의아니게 NPC 응답여부 체크에 걸리게 되므로 대화한 것으로 처리해 줌
|
|
|
|
return 1;
|
|
}
|
|
|
|
int api_ui_OpenCompoundItem(CDNUserBase* pUser, int nCompoundShopID)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#ifndef _FINAL_BUILD
|
|
std::wstring wszLog;
|
|
wszLog = FormatW( L"아이템 합성창 열기");
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszLog.size()*sizeof(WCHAR), L"", (WCHAR*)wszLog.c_str());
|
|
#endif
|
|
|
|
pUser->SendOpenCompoundItem(nCompoundShopID);
|
|
pUser->SetCalledNpcResponse(true, false); // 보통 클라이언트에 보내는 UI 개설 요청 이후 대화로 이어지지 않기 때문에 에러가 아닌데도 본의아니게 NPC 응답여부 체크에 걸리게 되므로 대화한 것으로 처리해 줌
|
|
|
|
return 1;
|
|
}
|
|
|
|
int api_ui_OpenCashShop(CDNUserBase* pUser)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#ifndef _FINAL_BUILD
|
|
std::wstring wszLog;
|
|
wszLog = FormatW( L"캐쉬 아이템 상점 열기");
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszLog.size()*sizeof(WCHAR), L"", (WCHAR*)wszLog.c_str());
|
|
#endif
|
|
|
|
pUser->SendOpenCashShop();
|
|
pUser->SetCalledNpcResponse(true, false); // 보통 클라이언트에 보내는 UI 개설 요청 이후 대화로 이어지지 않기 때문에 에러가 아닌데도 본의아니게 NPC 응답여부 체크에 걸리게 되므로 대화한 것으로 처리해 줌
|
|
|
|
return 1;
|
|
}
|
|
|
|
int api_ui_OpenGuildMgrBox(CDNUserBase* pUser, int nGuildMgrNo)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#ifndef _FINAL_BUILD
|
|
std::wstring wszLog;
|
|
wszLog = FormatW( L"길드 관리 대화상자 열기");
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszLog.size()*sizeof(WCHAR), L"", (WCHAR*)wszLog.c_str());
|
|
#endif
|
|
|
|
pUser->SendOpenGuildMgrBox(nGuildMgrNo);
|
|
pUser->SetCalledNpcResponse(true, false); // 보통 클라이언트에 보내는 UI 개설 요청 이후 대화로 이어지지 않기 때문에 에러가 아닌데도 본의아니게 NPC 응답여부 체크에 걸리게 되므로 대화한 것으로 처리해 줌
|
|
|
|
return 1;
|
|
}
|
|
|
|
int api_ui_OpenGacha_JP(CDNUserBase* pUser, int nGachaShopID)
|
|
{
|
|
#ifdef PRE_ADD_GACHA_JAPAN
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#ifndef _FINAL_BUILD
|
|
std::wstring wszLog;
|
|
wszLog = FormatW( L"일본 가챠폰 열기");
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszLog.size()*sizeof(WCHAR), L"", (WCHAR*)wszLog.c_str());
|
|
#endif
|
|
|
|
TGachaponData_JP* pGachaData = g_pDataManager->GetGachaponData_JP( nGachaShopID );
|
|
if( !pGachaData )
|
|
return -2;
|
|
|
|
pUser->m_nGachaponShopID = nGachaShopID;
|
|
pUser->SendGachaShopOpen_JP( nGachaShopID );
|
|
|
|
// 보통 클라이언트에 보내는 UI 개설 요청 이후 대화로 이어지지 않기 때문에 에러가 아닌데도 본의아니게 NPC 응답여부 체크에 걸리게 되므로 대화한 것으로 처리해 줌
|
|
pUser->SetCalledNpcResponse( true, false );
|
|
|
|
return 1;
|
|
#endif
|
|
return -3;
|
|
}
|
|
|
|
int api_ui_OpenGiveNpcPresent(CDNUserBase* pUser, int nNpcID)
|
|
{
|
|
#if defined( PRE_ADD_NPC_REPUTATION_SYSTEM )
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#ifndef _FINAL_BUILD
|
|
std::wstring wszLog;
|
|
wszLog = FormatW( L"NPC 선물하기 UI 열기");
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszLog.size()*sizeof(WCHAR), L"", (WCHAR*)wszLog.c_str());
|
|
#endif
|
|
|
|
// 클라이언트한테 npc 에게 선물하기 UI 띄우라고 패킷 보냄.
|
|
pUser->SendOpenGiveNpcPresent( nNpcID );
|
|
|
|
// 보통 클라이언트에 보내는 UI 개설 요청 이후 대화로 이어지지 않기 때문에 에러가 아닌데도 본의아니게 NPC 응답여부 체크에 걸리게 되므로 대화한 것으로 처리해 줌
|
|
// 그렇지만 npc 선물하기는 계속 대화가 이어지므로 그냥 놔둔다. 이거 호출하면 대화 다이얼로그가 바로 닫힌다.
|
|
//pUser->SetCalledNpcResponse( true, false );
|
|
|
|
return 1;
|
|
#else
|
|
return -1;
|
|
#endif
|
|
}
|
|
|
|
int api_ui_OpenDonation(CDNUserBase* pUser)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#if defined (PRE_ADD_DONATION)
|
|
pUser->SendOpenDonation();
|
|
pUser->SetCalledNpcResponse( true, false );
|
|
#endif // #if defined (PRE_ADD_DONATION)
|
|
|
|
return 1;
|
|
}
|
|
|
|
int api_ui_OpenInventory(CDNUserBase* pUser)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
pUser->SendOpenInventory();
|
|
pUser->SetCalledNpcResponse( true, false );
|
|
|
|
return 1;
|
|
}
|
|
|
|
int api_user_UserMessage(CDNUserBase* pUser, int nType, int nBaseStringIdx, lua_tinker::table ParamTable)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
std::vector<DNReplaceString::DynamicReplaceStringInfo> ReplaceParamList;
|
|
// 베이스 스트링 얻고
|
|
#if defined(PRE_ADD_MULTILANGUAGE)
|
|
std::wstring wszBaseString = GetEtUIXML().GetUIString( CEtUIXML::idCategory1, nBaseStringIdx, pUser->m_eSelectedLanguage );
|
|
#else //#if defined(PRE_ADD_MULTILANGUAGE)
|
|
std::wstring wszBaseString = GetEtUIXML().GetUIString( CEtUIXML::idCategory1, nBaseStringIdx );
|
|
#endif //#if defined(PRE_ADD_MULTILANGUAGE)
|
|
|
|
// 먼저 파라미터 테이블에 값이 있는지 확인 하고
|
|
lua_tinker::table t = ParamTable.get<lua_tinker::table>(1);
|
|
const char* __szKey = t.get<const char*>(1);
|
|
|
|
// 있으면
|
|
if ( __szKey )
|
|
{
|
|
for ( int i = 1 ; i <= ParamTable.getSize() ; i++ )
|
|
{
|
|
lua_tinker::table pTable = ParamTable.get<lua_tinker::table>(i);
|
|
char* szKey = pTable.get<char*>(1);
|
|
int nValueType = pTable.get<int>(2);
|
|
int nValue = pTable.get<int>(3);
|
|
|
|
DNReplaceString::DynamicReplaceStringInfo param;
|
|
ToWideString(szKey, param.szKey);
|
|
param.cValueType = (char)nValueType;
|
|
param.nValue = nValue;
|
|
ReplaceParamList.push_back(param);
|
|
}
|
|
}
|
|
|
|
#if defined(_SERVER) &&defined(PRE_ADD_MULTILANGUAGE)
|
|
g_ReplaceString.Relpace(wszBaseString, ReplaceParamList, pUser->m_eSelectedLanguage );
|
|
#else //#if defined(_SERVER) &&defined(PRE_ADD_MULTILANGUAGE)
|
|
g_ReplaceString.Relpace(wszBaseString, ReplaceParamList );
|
|
#endif //#if defined(_SERVER) &&defined(PRE_ADD_MULTILANGUAGE)
|
|
|
|
if ( wszBaseString.size() > 256)
|
|
return -3;
|
|
|
|
switch(nType)
|
|
{
|
|
case CHATTYPE_NORMAL:
|
|
case CHATTYPE_PARTY:
|
|
case CHATTYPE_PRIVATE:
|
|
case CHATTYPE_GUILD:
|
|
case CHATTYPE_CHANNEL:
|
|
case CHATTYPE_SYSTEM:
|
|
break;
|
|
default:
|
|
return -2;
|
|
}
|
|
|
|
pUser->SendChat((eChatType)nType, (int)wszBaseString.size()*sizeof(WCHAR), L"", (WCHAR*)wszBaseString.c_str());
|
|
|
|
return 1;
|
|
}
|
|
|
|
int api_quest_AddSymbolItem(CDNUserBase* pUser, int nItemID, short wCount)
|
|
{
|
|
/*
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
bool bResult = false;
|
|
if (pUser->GetItem()->AddSymbolItem(nItemID, wCount, 0, ITEMLOG_ADDQUESTINVEN) == ERROR_NONE) bResult = true;
|
|
|
|
#ifndef _FINAL_BUILD
|
|
std::wstring wszMsg;
|
|
wszMsg = FormatW( L"심볼아이템추가 %s ID:%d %d개" , bResult ? L"성공":L"실패", nItemID, (int)wCount);
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszMsg.size()*sizeof(WCHAR), L"", (WCHAR*)wszMsg.c_str());
|
|
#endif
|
|
*/
|
|
|
|
return 1;
|
|
}
|
|
|
|
int api_quest_DelSymbolItem(CDNUserBase* pUser, int nItemID, short wCount)
|
|
{
|
|
/*
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
bool bResult = false;
|
|
if (pUser->GetItem()->DelSymbolItem(nItemID, wCount, 0, ITEMLOG_DELETEQUESTINVEN) == ERROR_NONE) bResult = true;
|
|
|
|
#ifndef _FINAL_BUILD
|
|
std::wstring wszMsg;
|
|
wszMsg = FormatW( L"심볼아이템제거 %s ID:%d %d개" , bResult ? L"성공":L"실패", nItemID, (int)wCount);
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszMsg.size()*sizeof(WCHAR), L"", (WCHAR*)wszMsg.c_str());
|
|
#endif
|
|
*/
|
|
|
|
return 1;
|
|
}
|
|
|
|
int api_quest_HasSymbolItem(CDNUserBase* pUser, int nItemIndex, int nItemCnt)
|
|
{
|
|
/*
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
CDNUserItem* pUserItem = pUser->GetItem();
|
|
if ( !pUserItem )
|
|
return -2;
|
|
|
|
int nCount = pUserItem->ExistSymbolItemCount(nItemIndex);
|
|
#ifndef _FINAL_BUILD
|
|
std::wstring wszMsg;
|
|
wszMsg = FormatW( L"심볼아이템 조회 UserObjID: %d nItemID:%d %d개 %d개 있음" , nUserObjectID, nItemIndex, (int)nItemCnt, nCount);
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszMsg.size()*sizeof(WCHAR), L"", (WCHAR*)wszMsg.c_str());
|
|
#endif
|
|
|
|
if (nCount < nItemCnt)
|
|
{
|
|
return -3;
|
|
}
|
|
|
|
return nCount;
|
|
*/
|
|
|
|
return 0;
|
|
}
|
|
|
|
int api_quest_CheckQuestInvenForAddItem(CDNUserBase* pUser, int nItemIndex, int nItemCnt)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
CDNUserItem* pUserItem = pUser->GetItem();
|
|
if (!pUserItem) {
|
|
return -2;
|
|
}
|
|
|
|
#if defined (_VILLAGESERVER)
|
|
if (!pUserItem->IsValidSpaceQuestInventorySlot(nItemIndex, nItemCnt))
|
|
return -3;
|
|
#endif
|
|
|
|
#if defined (_GAMESERVER)
|
|
if (!pUserItem->IsValidSpaceQuestInventorySlot(nItemIndex, nItemCnt)) {
|
|
pUser->SendQuestResult(ERROR_QUEST_INVENTORY_NOTENOUGH);
|
|
return -3;
|
|
}
|
|
|
|
// 퀘스트 인벤토리 공간에 대한 별도의 체크와 사전알림 존재
|
|
int nResult = pUserItem->FindBlankQuestInventorySlotCount();
|
|
if (QUESTINVENBLANKCHECKMIN >= nResult) {
|
|
pUser->SendQuestResult(ERROR_QUEST_INVENTORY_ALMOSTFULL);
|
|
}
|
|
#endif
|
|
return 1;
|
|
}
|
|
|
|
int api_quest_CheckQuestInvenForAddItemList(CDNUserBase* pUser, lua_tinker::table ItemTable)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
CDNUserItem* pUserItem = pUser->GetItem();
|
|
if (!pUserItem) {
|
|
return -2;
|
|
}
|
|
|
|
TQuestItemCnt TempQuestInven[QUESTINVENTORYMAX];
|
|
{
|
|
// 임시 퀘스트 인벤토리에 현재 퀘스트 인벤토리의 아이템 개수 정보들을 복사
|
|
|
|
::memset(TempQuestInven, 0, sizeof(TempQuestInven));
|
|
|
|
for (int iIndex = 0 ; QUESTINVENTORYMAX > iIndex ; ++iIndex) {
|
|
const TQuestItem* pQuestItem = pUserItem->GetQuestInventory(iIndex);
|
|
if (pQuestItem) {
|
|
TempQuestInven[iIndex].Set(pQuestItem->nItemID, pQuestItem->wCount);
|
|
}
|
|
else {
|
|
TempQuestInven[iIndex].Reset();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (0 >= ItemTable.getSize()) {
|
|
// 아이템 테이블에 아무값도 없음 ?
|
|
DN_RETURN(false);
|
|
}
|
|
|
|
for (int iIndex = 1 ; ItemTable.getSize() >= iIndex ; ++iIndex) {
|
|
lua_tinker::table pTable = ItemTable.get<lua_tinker::table>(iIndex);
|
|
if (0 >= pTable.getSize()) {
|
|
continue;
|
|
}
|
|
|
|
bool bResult = __IsValidSpaceQuestInventorySlotAndSet(TempQuestInven, pTable.get<int>(1), pTable.get<int>(2));
|
|
if (!bResult) {
|
|
return -3;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int api_quest_AddQuestItem(CDNUserBase* pUser, int nItemID, short wCount, int nQuestID)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#if defined(_CH)
|
|
if (pUser->GetFCMState() != FCMSTATE_NONE){
|
|
pUser->SendQuestResult(ERROR_QUEST_FCM);
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
bool bResult = false;
|
|
if (pUser->GetItem()->AddQuestInventory(nItemID, wCount, nQuestID, DBDNWorldDef::AddMaterializedItem::QuestReward) == ERROR_NONE) bResult = true;
|
|
|
|
#ifndef _FINAL_BUILD
|
|
std::wstring wszMsg;
|
|
wszMsg = FormatW( L"퀘스트 아이템추가 %s ID:%d %d개" , bResult ? L"성공":L"실패", nItemID, (int)wCount);
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszMsg.size()*sizeof(WCHAR), L"", (WCHAR*)wszMsg.c_str());
|
|
#endif
|
|
|
|
return bResult ? 1 : 0;
|
|
}
|
|
|
|
int api_quest_DelQuestItem(CDNUserBase* pUser, int nItemID, short wCount, int nQuestID)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#if defined(_CH)
|
|
if (pUser->GetFCMState() != FCMSTATE_NONE){
|
|
pUser->SendQuestResult(ERROR_QUEST_FCM);
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
bool bResult = false;
|
|
if (pUser->GetItem()->DeleteQuestInventory(nItemID, wCount, nQuestID, DBDNWorldDef::UseItem::Destroy) == ERROR_NONE) bResult = true;
|
|
|
|
#ifndef _FINAL_BUILD
|
|
std::wstring wszMsg;
|
|
wszMsg = FormatW( L"퀘스트 아이템제거 %s ID:%d %d개" , bResult ? L"성공":L"실패", nItemID, (int)wCount);
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszMsg.size()*sizeof(WCHAR), L"", (WCHAR*)wszMsg.c_str());
|
|
#endif
|
|
|
|
return bResult ? 1 : 0;
|
|
}
|
|
|
|
int api_quest_AllDelQuestItem(CDNUserBase* pUser, int nItemID)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#if defined(_CH)
|
|
if (pUser->GetFCMState() != FCMSTATE_NONE){
|
|
pUser->SendQuestResult(ERROR_QUEST_FCM);
|
|
return -1;
|
|
}
|
|
#endif
|
|
bool bResult = false;
|
|
|
|
CDNUserItem* pUserItem = pUser->GetItem();
|
|
if ( !pUserItem )
|
|
return -2;
|
|
|
|
int nCount = pUserItem->GetQuestInventoryItemCount(nItemID);
|
|
|
|
if (pUser->GetItem()->DeleteQuestInventory(nItemID, nCount, 0, DBDNWorldDef::UseItem::Destroy) == ERROR_NONE) bResult = true;
|
|
|
|
#ifndef _FINAL_BUILD
|
|
std::wstring wszMsg;
|
|
wszMsg = FormatW( L"퀘스트 아이템제거 %s ID:%d %d개" , bResult ? L"성공":L"실패", nItemID, (int)nCount);
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszMsg.size()*sizeof(WCHAR), L"", (WCHAR*)wszMsg.c_str());
|
|
#endif
|
|
|
|
return bResult ? 1 : 0;
|
|
}
|
|
|
|
int api_quest_HasQuestItem(CDNUserBase* pUser, int nItemIndex, int nItemCnt)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
CDNUserItem* pUserItem = pUser->GetItem();
|
|
if ( !pUserItem )
|
|
return -2;
|
|
|
|
int nCount = pUserItem->GetQuestInventoryItemCount(nItemIndex);
|
|
#ifndef _FINAL_BUILD
|
|
|
|
//만약 빌리지, 게임 둘다 아니면 컴파일 에러.
|
|
#if defined(_VILLAGESERVER)
|
|
UINT nUserID = static_cast<CDNUserSession*>(pUser)->GetObjectID();
|
|
#endif
|
|
|
|
#if defined(_GAMESERVER)
|
|
UINT nUserID = static_cast<CDNUserSession*>(pUser)->GetSessionID();
|
|
#endif
|
|
std::wstring wszMsg;
|
|
wszMsg = FormatW( L"퀘스트 아이템 조회 UserObjID: %d nItemID:%d %d개 %d개 있음" , nUserID, nItemIndex, (int)nItemCnt, nCount);
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszMsg.size()*sizeof(WCHAR), L"", (WCHAR*)wszMsg.c_str());
|
|
#endif
|
|
|
|
if (nCount < nItemCnt)
|
|
{
|
|
return -3;
|
|
}
|
|
|
|
return nCount;
|
|
}
|
|
|
|
int api_ui_OpenGuildCreate(CDNUserBase* pUser)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
// N/A
|
|
|
|
return 1;
|
|
}
|
|
|
|
int api_ui_OpenQuestReward(CDNUserBase* pUser, int nRewardTableIndex, bool bActivate)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
pUser->SendOpenQuestReward(nRewardTableIndex, bActivate);
|
|
pUser->SetCalledNpcResponse(true, false); // 보통 클라이언트에 보내는 UI 개설 요청 이후 대화로 이어지지 않기 때문에 에러가 아닌데도 본의아니게 NPC 응답여부 체크에 걸리게 되므로 대화한 것으로 처리해 줌
|
|
|
|
return 1;
|
|
}
|
|
|
|
int api_quest_RewardQuestUser(CDNUserBase* pUser, int nRewardTableIndext, int nQuestID, int nRewardCheck)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#if defined(_CH)
|
|
if (pUser->GetFCMState() != FCMSTATE_NONE){
|
|
pUser->SendQuestResult(ERROR_QUEST_FCM);
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
CDNUserItem* pUserItem = pUser->GetItem();
|
|
if (!pUserItem) {
|
|
return -2;
|
|
}
|
|
|
|
// 퀘스트 보상 테이블을 참조해서
|
|
TQuestReward table;
|
|
bool bResult = g_pDataManager->GetQuestReward(nRewardTableIndext, table);
|
|
if (!bResult) {
|
|
return -4;
|
|
}
|
|
|
|
DN_ASSERT(0 < table.nQuestID, "Invalid!");
|
|
DN_ASSERT(0 < table.nQuestStep, "Invalid!");
|
|
|
|
if (table.nQuestStep != pUser->GetQuest()->GetQuestStep(table.nQuestID) || (table.nClass != 0 && table.nClass != pUser->GetClassID()))
|
|
{
|
|
return -5;
|
|
}
|
|
|
|
ZeroMemory(table.LevelCapItemArray, sizeof(table.LevelCapItemArray));
|
|
if (pUser->GetLevel() >= (int)CGlobalWeightTable::GetInstance().GetValue(CGlobalWeightTable::PlayerLevelLimit))
|
|
{
|
|
CDNQuest* pQuest = g_pQuestManager->GetQuest(table.nQuestID);
|
|
if(!pQuest)
|
|
return -6;
|
|
|
|
if (pQuest->IsLevelCapReward())
|
|
{
|
|
const TQuestLevelCapReward* pLevelCapReward = g_pDataManager->GetQuestLevelCapReward(pQuest->GetQuestInfo().cQuestType, pUser->GetClassID());
|
|
if (!pLevelCapReward)
|
|
{
|
|
#if !defined (_FINAL_BUILD)
|
|
wstring wszMsg;
|
|
wszMsg = FormatW( L"퀘스트 레벨캡 보상 테이블 조회 실패 퀘스트ID:%d 타입:%d 클래스ID:%d ", table.nQuestID, pQuest->GetQuestInfo().cQuestType, pUser->GetClassID());
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszMsg.size()*sizeof(WCHAR), L"", (WCHAR*)wszMsg.c_str());
|
|
#endif // #if !defined (_FINAL_BUILD)
|
|
return -7;
|
|
}
|
|
|
|
CopyMemory(table.LevelCapItemArray, pLevelCapReward->Items, sizeof(pLevelCapReward->Items));
|
|
}
|
|
}
|
|
|
|
if (pUser->GetQuest()) {
|
|
pUser->GetQuest()->SetReward(table, nQuestID, nRewardCheck);
|
|
|
|
#ifndef _FINAL_BUILD
|
|
//만약 빌리지, 게임 둘다 아니면 컴파일 에러.
|
|
#if defined (_VILLAGESERVER)
|
|
UINT nUserObjectID = static_cast<CDNUserSession*>(pUser)->GetObjectID();
|
|
#endif
|
|
|
|
#if defined (_GAMESERVER)
|
|
UINT nUserObjectID = static_cast<CDNUserSession*>(pUser)->GetSessionID();
|
|
#endif
|
|
std::wstring wszMsg;
|
|
wszMsg = FormatW( L"보상 세팅UserObjID: %d 테이블ID:%d 퀘스트IDL%d " ,
|
|
nUserObjectID, nRewardTableIndext, nQuestID);
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszMsg.size()*sizeof(WCHAR), L"", (WCHAR*)wszMsg.c_str());
|
|
#endif
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int api_user_GetMapIndex(CDNUserBase* pUser)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
return pUser->GetMapIndex();
|
|
}
|
|
|
|
int api_user_GetLastStageClearRank(CDNUserBase* pUser)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
return pUser->GetLastStageClearRank();
|
|
}
|
|
|
|
int api_user_EnoughCoin(CDNUserBase* pUser, int nCoin)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#if defined(_CH)
|
|
if (pUser->GetFCMState() != FCMSTATE_NONE){
|
|
pUser->SendQuestResult(ERROR_QUEST_FCM);
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
if( pUser->GetCoin() < (INT64)nCoin )
|
|
return -2;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int api_user_GetCoin(CDNUserBase* pUser)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#if defined(_CH)
|
|
if (pUser->GetFCMState() != FCMSTATE_NONE){
|
|
pUser->SendQuestResult(ERROR_QUEST_FCM);
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
return static_cast<int>(pUser->GetCoin());
|
|
}
|
|
|
|
int api_user_IsMissionGained(CDNUserBase* pUser, int nMissionIndex)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#if defined(_CH)
|
|
if (pUser->GetFCMState() != FCMSTATE_NONE){
|
|
pUser->SendQuestResult(ERROR_QUEST_FCM);
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
// 해당 미션이 없거나 비활성화 상태이면 실패
|
|
TMissionData *pData = g_pDataManager->GetMissionData(nMissionIndex);
|
|
if (!pData || !pData->bActivate) return 0;
|
|
|
|
return(GetBitFlag(pUser->GetMissionData()->MissionGain, nMissionIndex));
|
|
}
|
|
|
|
int api_user_IsMissionAchieved(CDNUserBase* pUser, int nMissionIndex)
|
|
{
|
|
DN_ASSERT(CHECK_LIMIT(nMissionIndex, MISSIONMAX), "Invalid!");
|
|
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#if defined(_CH)
|
|
if (pUser->GetFCMState() != FCMSTATE_NONE){
|
|
pUser->SendQuestResult(ERROR_QUEST_FCM);
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
// 해당 미션이 없거나 비활성화 상태이면 실패
|
|
TMissionData *pData = g_pDataManager->GetMissionData(nMissionIndex);
|
|
if (!pData || !pData->bActivate) {
|
|
return 0;
|
|
}
|
|
|
|
return(GetBitFlag(pUser->GetMissionData()->MissionAchieve, nMissionIndex));
|
|
}
|
|
|
|
int api_user_HasItemWarehouse(CDNUserBase* pUser, int nItemIndex, int nItemCnt)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#if defined(_CH)
|
|
if (pUser->GetFCMState() != FCMSTATE_NONE){
|
|
pUser->SendQuestResult(ERROR_QUEST_FCM);
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
const CDNUserItem* pUserItem = pUser->GetItem();
|
|
if (!pUserItem) {
|
|
return -2;
|
|
}
|
|
|
|
int nCount = pUserItem->GetWarehouseItemCount(nItemIndex);
|
|
if (nCount < nItemCnt) {
|
|
return -3;
|
|
}
|
|
|
|
return nCount;
|
|
}
|
|
|
|
int api_user_HasItemEquip(CDNUserBase* pUser, int nItemIndex)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#if defined(_CH)
|
|
if (pUser->GetFCMState() != FCMSTATE_NONE){
|
|
pUser->SendQuestResult(ERROR_QUEST_FCM);
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
const CDNUserItem* pUserItem = pUser->GetItem();
|
|
if (!pUserItem) {
|
|
return -2;
|
|
}
|
|
|
|
bool bResult = pUserItem->CheckEquipByItemID(nItemIndex);
|
|
if (!bResult) {
|
|
return -2;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int api_guild_GetGuildMemberRole(CDNUserBase* pUser)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#if defined(_CH)
|
|
if (pUser->GetFCMState() != FCMSTATE_NONE){
|
|
pUser->SendQuestResult(ERROR_QUEST_FCM);
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
if (pUser->GetGuildSelfView().IsSet()) {
|
|
return(pUser->GetGuildSelfView().btGuildRole + 1);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int api_quest_IncQuestMemo(CDNUserBase* pUser, int nQuestID, char nMemoIndex)
|
|
{
|
|
if (!pUser)
|
|
return LONG_MIN;
|
|
|
|
#if defined(_CH)
|
|
if (pUser->GetFCMState() != FCMSTATE_NONE){
|
|
pUser->SendQuestResult(ERROR_QUEST_FCM);
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
if (!CHECK_RANGE(nMemoIndex, 1, QUESTMEMOMAX)) {
|
|
// 퀘스트 메모 인덱스 범위를 벗어남 (1~10)
|
|
DN_RETURN(LONG_MIN);
|
|
}
|
|
|
|
if (QUESTMEMOREWARDCHECK == nMemoIndex) {
|
|
// 퀘스트 보상 무한지급을 방지하기 위하여 할당받은 인덱스는 사용할 수 없음
|
|
DN_RETURN(LONG_MIN);
|
|
}
|
|
|
|
return pUser->GetQuest()->IncQuestMemo(nQuestID, nMemoIndex-1);
|
|
}
|
|
|
|
int api_quest_DecQuestMemo(CDNUserBase* pUser, int nQuestID, char nMemoIndex)
|
|
{
|
|
if (!pUser)
|
|
return LONG_MAX;
|
|
|
|
#if defined(_CH)
|
|
if (pUser->GetFCMState() != FCMSTATE_NONE){
|
|
pUser->SendQuestResult(ERROR_QUEST_FCM);
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
if (!CHECK_RANGE(nMemoIndex, 1, QUESTMEMOMAX)) {
|
|
// 퀘스트 메모 인덱스 범위를 벗어남 (1~10)
|
|
DN_RETURN(LONG_MAX);
|
|
}
|
|
|
|
if (QUESTMEMOREWARDCHECK == nMemoIndex) {
|
|
// 퀘스트 보상 무한지급을 방지하기 위하여 할당받은 인덱스는 사용할 수 없음
|
|
DN_RETURN(LONG_MAX);
|
|
}
|
|
|
|
return pUser->GetQuest()->DecQuestMemo(nQuestID, nMemoIndex-1);
|
|
}
|
|
|
|
int api_user_SetUserJobID(CDNUserBase* pUser, int nJobID)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#if defined(_CH)
|
|
if (pUser->GetFCMState() != FCMSTATE_NONE){
|
|
pUser->SendQuestResult(ERROR_QUEST_FCM);
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
if (nJobID == pUser->GetUserJob()) {
|
|
return 0;
|
|
}
|
|
|
|
DNTableFileFormat* pJobTable = GetDNTable( CDnTableDB::TJOB );
|
|
|
|
// 현재 직업의 단계값과 루트 직업을 얻어옴.
|
|
int iNowJob = pUser->GetUserJob();
|
|
int iNowJobDeep = 0;
|
|
int iNowRootJob = 0;
|
|
for( int i = 0; i < pJobTable->GetItemCount(); ++i )
|
|
{
|
|
int iItemID = pJobTable->GetItemID( i );
|
|
if( iItemID == iNowJob )
|
|
{
|
|
iNowJobDeep = pJobTable->GetFieldFromLablePtr( iItemID, "_JobNumber" )->GetInteger();
|
|
iNowRootJob = pJobTable->GetFieldFromLablePtr( iItemID, "_BaseClass" )->GetInteger();
|
|
break;
|
|
}
|
|
}
|
|
|
|
// 바꾸기 원하는 직업과 단계가 같거나 큰지 확인.
|
|
bool bSuccess = false;
|
|
map<int, int> mapRootJob;
|
|
for( int i = 0; i < pJobTable->GetItemCount(); ++i )
|
|
{
|
|
int iItemID = pJobTable->GetItemID( i );
|
|
if( iItemID == nJobID )
|
|
{
|
|
int iJobRootToChange = pJobTable->GetFieldFromLablePtr( iItemID, "_BaseClass" )->GetInteger();
|
|
if( iNowRootJob == iJobRootToChange )
|
|
{
|
|
int iJobDeepToChange = pJobTable->GetFieldFromLablePtr( iItemID, "_JobNumber" )->GetInteger();
|
|
if( iNowJobDeep < iJobDeepToChange )
|
|
{
|
|
// 부모 직업도 맞아야 함.
|
|
int iParentJobID = pJobTable->GetFieldFromLablePtr( iItemID, "_ParentJob" )->GetInteger();
|
|
if( iParentJobID == iNowJob )
|
|
{
|
|
pUser->SetUserJob( nJobID );
|
|
bSuccess = true;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// 바꾸고자 하는 직업의 부모 직업이 현재 직업이 아님.
|
|
#ifndef _FINAL_BUILD
|
|
wstring wszString = FormatW(L"현재 직업에선 전직 할 수 없는 직업입니다.!!\r\n");
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszString.size()*sizeof(WCHAR), L"", (WCHAR*)wszString.c_str());
|
|
#endif // _FINAL_BUILD
|
|
return -3;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// 바꾸고자하는 직업이 아래 단계임. 못바꿈.
|
|
#ifndef _FINAL_BUILD
|
|
wstring wszString = FormatW(L"같거나 낮은 단계의 직업으로 바꿀 수 없습니다!!\r\n");
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszString.size()*sizeof(WCHAR), L"", (WCHAR*)wszString.c_str());
|
|
#endif // _FINAL_BUILD
|
|
return -3;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// 바꾸고자하는 직업이 다른 클래스임. 못바꿈.
|
|
#ifndef _FINAL_BUILD
|
|
wstring wszString = FormatW(L"다른 클래스의 직업으로 바꿀 수 없습니다!!\r\n");
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszString.size()*sizeof(WCHAR), L"", (WCHAR*)wszString.c_str());
|
|
#endif // _FINAL_BUILD
|
|
return -3;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( false == bSuccess )
|
|
{
|
|
#ifndef _FINAL_BUILD
|
|
wstring wszString = FormatW(L"잘못된 Job ID 입니다..\r\n");
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszString.size()*sizeof(WCHAR), L"", (WCHAR*)wszString.c_str());
|
|
#endif // _FINAL_BUILD
|
|
return -2;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int api_user_IsJobInSameLine(CDNUserBase* pUser, int nBaseJobID)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
DNTableFileFormat* pSox = GetDNTable(CDnTableDB::TJOB);
|
|
if (!pSox) {
|
|
g_Log.Log( LogType::_FILELOG, L"JobTable.ext failed\r\n");
|
|
return -2;
|
|
}
|
|
|
|
int nJobID = pUser->GetUserJob();
|
|
if (!pSox->IsExistItem(nJobID)) {
|
|
return 0;
|
|
}
|
|
|
|
do {
|
|
if (nBaseJobID == nJobID) {
|
|
return 1;
|
|
}
|
|
|
|
DNTableCell *pSoxField = pSox->GetFieldFromLablePtr(nJobID, "_ParentJob");
|
|
if (!pSoxField) {
|
|
break;
|
|
}
|
|
|
|
nJobID = pSoxField->GetInteger();
|
|
if (0 >= nJobID) {
|
|
break;
|
|
}
|
|
|
|
} while(1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int api_user_HasCashItem(CDNUserBase* pUser, int nItemIndex, int nItemCnt)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
CDNUserItem* pUserItem = pUser->GetItem();
|
|
if ( !pUserItem )
|
|
return -2;
|
|
|
|
int nCount = pUserItem->GetCashItemCountByItemID(nItemIndex);
|
|
if (nCount < nItemCnt)
|
|
{
|
|
return -3;
|
|
}
|
|
|
|
return nCount;
|
|
}
|
|
|
|
int api_user_HasCashItemEquip(CDNUserBase* pUser, int nItemIndex)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#if defined(_CH)
|
|
if (pUser->GetFCMState() != FCMSTATE_NONE){
|
|
pUser->SendQuestResult(ERROR_QUEST_FCM);
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
const CDNUserItem* pUserItem = pUser->GetItem();
|
|
if (!pUserItem) {
|
|
return -2;
|
|
}
|
|
|
|
bool bResult = pUserItem->IsEquipCashItemExist(nItemIndex);
|
|
if (!bResult) {
|
|
return -2;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int api_quest_IncCounting(CDNUserBase* pUser, int nCountingType, int nCountingIndex)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
pUser->GetQuest()->OnCounting(nCountingType, nCountingIndex);
|
|
|
|
return 1;
|
|
}
|
|
|
|
int api_quest_IsPlayingQuestMaximum(CDNUserBase* pUser)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
if (MAX_PLAY_QUEST <= pUser->GetQuest()->GetPlayingQuestCount()) {
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int api_quest_ForceCompleteQuest(CDNUserBase* pUser, int nQuestID, int nQuestCode, int bDoMark, int bDoDelete, int bDoRepeat)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
CDNUserQuest* pQuest = pUser->GetQuest();
|
|
if (!pQuest) {
|
|
return -2;
|
|
}
|
|
|
|
int aRetVal = pQuest->ForceCompleteQuest(nQuestID, nQuestCode, bDoMark, bDoDelete, bDoRepeat);
|
|
if (1 != aRetVal) {
|
|
// 오류 발생
|
|
}
|
|
|
|
return aRetVal;
|
|
}
|
|
|
|
int api_npc_GetFavorPoint(CDNUserBase* pUser, int iNpcID)
|
|
{
|
|
#if defined( PRE_ADD_NPC_REPUTATION_SYSTEM )
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
CReputationSystemRepository* pReputationSystem = pUser->GetReputationSystem();
|
|
if( !pReputationSystem )
|
|
return -2;
|
|
|
|
return static_cast<int>(pReputationSystem->GetNpcReputation( iNpcID, IReputationSystem::NpcFavor ));
|
|
#else
|
|
return -1;
|
|
#endif // #if defined( PRE_ADD_NPC_REPUTATION_SYSTEM )
|
|
}
|
|
|
|
int api_npc_GetMalicePoint(CDNUserBase* pUser, int iNpcID)
|
|
{
|
|
#if defined( PRE_ADD_NPC_REPUTATION_SYSTEM )
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
CReputationSystemRepository* pReputationSystem = pUser->GetReputationSystem();
|
|
if( !pReputationSystem )
|
|
return -2;
|
|
|
|
return static_cast<int>(pReputationSystem->GetNpcReputation( iNpcID, IReputationSystem::NpcMalice ));
|
|
#else
|
|
return -1;
|
|
#endif // #if defined( PRE_ADD_NPC_REPUTATION_SYSTEM )
|
|
}
|
|
|
|
int api_npc_GetFavorPercent(CDNUserBase* pUser, int iNpcID)
|
|
{
|
|
#if defined( PRE_ADD_NPC_REPUTATION_SYSTEM )
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
CReputationSystemRepository* pReputationSystem = pUser->GetReputationSystem();
|
|
if( !pReputationSystem )
|
|
return -2;
|
|
|
|
return pReputationSystem->GetNpcReputationPercent( iNpcID, IReputationSystem::NpcFavor );
|
|
#else
|
|
return -1;
|
|
#endif // #if defined( PRE_ADD_NPC_REPUTATION_SYSTEM )
|
|
}
|
|
|
|
int api_npc_GetMalicePercent(CDNUserBase* pUser, int iNpcID )
|
|
{
|
|
#if defined( PRE_ADD_NPC_REPUTATION_SYSTEM )
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
CReputationSystemRepository* pReputationSystem = pUser->GetReputationSystem();
|
|
if( !pReputationSystem )
|
|
return -2;
|
|
|
|
return pReputationSystem->GetNpcReputationPercent( iNpcID, IReputationSystem::NpcMalice );
|
|
#else
|
|
return -1;
|
|
#endif // #if defined( PRE_ADD_NPC_REPUTATION_SYSTEM )
|
|
}
|
|
|
|
int api_npc_AddFavorPoint(CDNUserBase* pUser, int iNpcID, int val)
|
|
{
|
|
#if defined( PRE_ADD_NPC_REPUTATION_SYSTEM )
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
CReputationSystemRepository* pReputationSystem = pUser->GetReputationSystem();
|
|
if( !pReputationSystem )
|
|
return -2;
|
|
|
|
CNpcReputationProcessor::Process( static_cast<CDNUserSession*>(pUser), iNpcID, IReputationSystem::NpcFavor, val );
|
|
return 1;
|
|
#else
|
|
return -1;
|
|
#endif // #if defined( PRE_ADD_NPC_REPUTATION_SYSTEM )
|
|
}
|
|
|
|
int api_npc_AddMalicePoint(CDNUserBase* pUser, int iNpcID, int val)
|
|
{
|
|
#if defined( PRE_ADD_NPC_REPUTATION_SYSTEM )
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
CReputationSystemRepository* pReputationSystem = pUser->GetReputationSystem();
|
|
if( !pReputationSystem )
|
|
return -2;
|
|
|
|
CNpcReputationProcessor::Process( static_cast<CDNUserSession*>(pUser), iNpcID, IReputationSystem::NpcMalice, val );
|
|
return 1;
|
|
#else
|
|
return -1;
|
|
#endif // #if defined( PRE_ADD_NPC_REPUTATION_SYSTEM )
|
|
}
|
|
|
|
int api_npc_SendSelectedPresent(CDNUserBase* pUser, int iNpcID )
|
|
{
|
|
#if defined( PRE_ADD_NPC_REPUTATION_SYSTEM )
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
// 클라이언트에게 선택된 선물의 정보를 보내라고 패킷 보낸다.
|
|
pUser->SendRequestSendSelectedPresent( iNpcID );
|
|
|
|
return 1;
|
|
#else
|
|
return -1;
|
|
#endif // #if defined( PRE_ADD_NPC_REPUTATION_SYSTEM )
|
|
}
|
|
|
|
int api_npc_Rage(CDNUserBase* pUser, int iNpcID)
|
|
{
|
|
#if defined( PRE_ADD_NPC_REPUTATION_SYSTEM )
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
pUser->SendShowNpcEffect( iNpcID, 0 );
|
|
|
|
return 1;
|
|
#else
|
|
return -1;
|
|
#endif // #if defined( PRE_ADD_NPC_REPUTATION_SYSTEM )
|
|
}
|
|
|
|
int api_npc_Disappoint(CDNUserBase* pUser, int iNpcID)
|
|
{
|
|
#if defined( PRE_ADD_NPC_REPUTATION_SYSTEM )
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
pUser->SendShowNpcEffect( iNpcID, 1 );
|
|
|
|
return 1;
|
|
#else
|
|
return -1;
|
|
#endif // #if defined( PRE_ADD_NPC_REPUTATION_SYSTEM )
|
|
}
|
|
|
|
int api_user_RepairItem(CDNUserBase* pUser, int iAllRepair)
|
|
{
|
|
#if defined(PRE_ADD_REPAIR_NPC)
|
|
if (!pUser)
|
|
return -1;
|
|
int nRet = ERROR_NONE;
|
|
if( iAllRepair )
|
|
{
|
|
nRet = pUser->GetItem()->CheckRepairAll(false);
|
|
if( nRet == ERROR_NONE )
|
|
pUser->SendRepairAll(ERROR_NONE);
|
|
}
|
|
else
|
|
{
|
|
nRet = pUser->GetItem()->CheckRepairEquip(0);
|
|
if( nRet == ERROR_NONE )
|
|
pUser->SendRepairEquip(ERROR_NONE);
|
|
}
|
|
|
|
if( nRet == ERROR_NONE)
|
|
return 2; //아이템 수리 완료
|
|
else if( nRet == ERROR_ITEM_REPAIR)
|
|
return 0; // 수리할 아이템 없음
|
|
else if( nRet == ERROR_ITEM_INSUFFICIENCY_MONEY)
|
|
return 1; // 소지금 부족
|
|
return -1;
|
|
#else
|
|
return -1;
|
|
#endif
|
|
}
|
|
|
|
int api_ui_OpenExchangeEnchant(CDNUserBase* pUser)
|
|
{
|
|
#ifdef PRE_ADD_EXCHANGE_ENCHANT
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
#ifndef _FINAL_BUILD
|
|
std::wstring wszLog;
|
|
wszLog = FormatW( L"강화이동 오픈");
|
|
pUser->SendChat(CHATTYPE_NORMAL, (int)wszLog.size()*sizeof(WCHAR), L"", (WCHAR*)wszLog.c_str());
|
|
#endif
|
|
|
|
pUser->SendOpenExchangeEnchant();
|
|
pUser->SetCalledNpcResponse(true, false); // 보통 클라이언트에 보내는 UI 개설 요청 이후 대화로 이어지지 않기 때문에 에러가 아닌데도 본의아니게 NPC 응답여부 체크에 걸리게 되므로 대화한 것으로 처리해 줌
|
|
|
|
return 1;
|
|
#else
|
|
return -1;
|
|
#endif
|
|
}
|
|
|
|
int api_env_CheckCloseGateByTime(int iMapID)
|
|
{
|
|
#ifdef PRE_ADD_CHALLENGE_DARKLAIR
|
|
return g_pDataManager->IsCloseGateByTime(iMapID);
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
#if defined(PRE_ADD_OPEN_QUEST_TEXTURE_DIALOG)
|
|
int api_Open_Texture_Dialog(CDNUserBase* pUser, SCOpenTextureDialog data)
|
|
{
|
|
if(!pUser)
|
|
return -1;
|
|
|
|
pUser->SetCalledNpcResponse(true, true); // 보통 클라이언트에 보내는 UI 개설 요청 이후 대화로 이어지지 않기 때문에 에러가 아닌데도 본의아니게 NPC 응답여부 체크에 걸리게 되므로 대화한 것으로 처리해 줌
|
|
pUser->SendOpenTextureDialog(data);
|
|
return 1;
|
|
}
|
|
|
|
int api_Close_Texture_Dialog(CDNUserBase* pUser, int nDlgID)
|
|
{
|
|
if(!pUser)
|
|
return -1;
|
|
|
|
pUser->SetCalledNpcResponse(true, true); // 보통 클라이언트에 보내는 UI 개설 요청 이후 대화로 이어지지 않기 때문에 에러가 아닌데도 본의아니게 NPC 응답여부 체크에 걸리게 되므로 대화한 것으로 처리해 줌
|
|
pUser->SendCloseTextureDialog(nDlgID);
|
|
return 1;
|
|
}
|
|
#endif
|
|
int api_quest_WorldBuffCheck(int nItemID)
|
|
{
|
|
#if defined( PRE_DRAGONBUFF )
|
|
if( g_pDataManager )
|
|
{
|
|
if( g_pDataManager->bIsWorldBuffData(nItemID) )
|
|
return 1;
|
|
}
|
|
#endif
|
|
return -1;
|
|
}
|
|
|
|
int api_quest_ApplyWorldBuff(CDNUserBase* pUser, int nItemID, int nMapIdx)
|
|
{
|
|
if(!pUser)
|
|
return -1;
|
|
#if defined(_VILLAGESERVER) && defined( PRE_DRAGONBUFF )
|
|
if( g_pUserSessionManager )
|
|
{
|
|
if( g_pDataManager )
|
|
{
|
|
g_pDataManager->AddWorldBuffData(nItemID);
|
|
}
|
|
g_pUserSessionManager->ApplyWorldBuff( pUser->GetCharacterName(), nItemID, nMapIdx);
|
|
}
|
|
|
|
if( g_pMasterConnection && g_pMasterConnection->GetActive() )
|
|
{
|
|
g_pMasterConnection->SendApplyWorldBuff( pUser->GetCharacterName(), nItemID, nMapIdx );
|
|
}
|
|
#endif
|
|
return -1;
|
|
}
|
|
|
|
int api_Open_ChangeJobDialog(CDNUserBase* pUser)
|
|
{
|
|
if (!pUser)
|
|
return -1;
|
|
|
|
pUser->SetCalledNpcResponse(true, true); // 보통 클라이언트에 보내는 UI 개설 요청 이후 대화로 이어지지 않기 때문에 에러가 아닌데도 본의아니게 NPC 응답여부 체크에 걸리게 되므로 대화한 것으로 처리해 줌
|
|
pUser->SendOpenChangeJobDialog();
|
|
return 1;
|
|
}
|
|
} |