|
|
|
|
@@ -5841,6 +5841,29 @@ void CHARACTER::GiveGold(int iAmount)
|
|
|
|
|
|
|
|
|
|
bool CHARACTER::PickupItem(DWORD dwVID)
|
|
|
|
|
{
|
|
|
|
|
if (!CanHandleItem())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
const DWORD dwNow = get_dword_time();
|
|
|
|
|
|
|
|
|
|
if (m_dwPickupWindowStart == 0 || dwNow - m_dwPickupWindowStart >= 1000)
|
|
|
|
|
{
|
|
|
|
|
m_dwPickupWindowStart = dwNow;
|
|
|
|
|
m_iPickupWindowCount = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
++m_iPickupWindowCount;
|
|
|
|
|
|
|
|
|
|
if (m_iPickupWindowCount > 25)
|
|
|
|
|
{
|
|
|
|
|
char szDetail[96];
|
|
|
|
|
snprintf(szDetail, sizeof(szDetail), "count=%d window_ms=%u", m_iPickupWindowCount, dwNow - m_dwPickupWindowStart);
|
|
|
|
|
RecordAntiCheatViolation("PICKUP_RATE", MIN(8, 1 + (m_iPickupWindowCount - 25) / 5), szDetail, m_iPickupWindowCount > 45);
|
|
|
|
|
|
|
|
|
|
if (m_iPickupWindowCount > 45)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LPITEM item = ITEM_MANAGER::instance().FindByVID(dwVID);
|
|
|
|
|
|
|
|
|
|
if (IsObserverMode())
|
|
|
|
|
@@ -5849,104 +5872,114 @@ bool CHARACTER::PickupItem(DWORD dwVID)
|
|
|
|
|
if (!item || !item->GetSectree())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (item->DistanceValid(this))
|
|
|
|
|
const int iDist = DISTANCE_APPROX(item->GetX() - GetX(), item->GetY() - GetY());
|
|
|
|
|
|
|
|
|
|
if (!item->DistanceValid(this))
|
|
|
|
|
{
|
|
|
|
|
if (item->IsOwnership(this))
|
|
|
|
|
char szDetail[128];
|
|
|
|
|
snprintf(szDetail, sizeof(szDetail), "item=%u dist=%d owner=%u", item->GetVID(), iDist, item->GetOwnershipPID());
|
|
|
|
|
RecordAntiCheatViolation("PICKUP_DISTANCE", iDist > 900 ? 12 : 4, szDetail, iDist > 900);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (item->IsOwnership(this))
|
|
|
|
|
{
|
|
|
|
|
// 만약 주으려 하는 아이템이 엘크라면
|
|
|
|
|
if (item->GetType() == ITEM_ELK)
|
|
|
|
|
{
|
|
|
|
|
// 만약 주으려 하는 아이템이 엘크라면
|
|
|
|
|
if (item->GetType() == ITEM_ELK)
|
|
|
|
|
{
|
|
|
|
|
GiveGold(item->GetCount());
|
|
|
|
|
item->RemoveFromGround();
|
|
|
|
|
GiveGold(item->GetCount());
|
|
|
|
|
item->RemoveFromGround();
|
|
|
|
|
|
|
|
|
|
M2_DESTROY_ITEM(item);
|
|
|
|
|
M2_DESTROY_ITEM(item);
|
|
|
|
|
|
|
|
|
|
Save();
|
|
|
|
|
}
|
|
|
|
|
// 평범한 아이템이라면
|
|
|
|
|
else
|
|
|
|
|
Save();
|
|
|
|
|
}
|
|
|
|
|
// 평범한 아이템이라면
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (item->IsStackable() && !IS_SET(item->GetAntiFlag(), ITEM_ANTIFLAG_STACK))
|
|
|
|
|
{
|
|
|
|
|
if (item->IsStackable() && !IS_SET(item->GetAntiFlag(), ITEM_ANTIFLAG_STACK))
|
|
|
|
|
BYTE bCount = item->GetCount();
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < INVENTORY_MAX_NUM; ++i)
|
|
|
|
|
{
|
|
|
|
|
BYTE bCount = item->GetCount();
|
|
|
|
|
LPITEM item2 = GetInventoryItem(i);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < INVENTORY_MAX_NUM; ++i)
|
|
|
|
|
if (!item2)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (item2->GetVnum() == item->GetVnum())
|
|
|
|
|
{
|
|
|
|
|
LPITEM item2 = GetInventoryItem(i);
|
|
|
|
|
int j;
|
|
|
|
|
|
|
|
|
|
if (!item2)
|
|
|
|
|
for (j = 0; j < ITEM_SOCKET_MAX_NUM; ++j)
|
|
|
|
|
if (item2->GetSocket(j) != item->GetSocket(j))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (j != ITEM_SOCKET_MAX_NUM)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (item2->GetVnum() == item->GetVnum())
|
|
|
|
|
BYTE bCount2 = MIN(200 - item2->GetCount(), bCount);
|
|
|
|
|
bCount -= bCount2;
|
|
|
|
|
|
|
|
|
|
item2->SetCount(item2->GetCount() + bCount2);
|
|
|
|
|
|
|
|
|
|
if (bCount == 0)
|
|
|
|
|
{
|
|
|
|
|
int j;
|
|
|
|
|
|
|
|
|
|
for (j = 0; j < ITEM_SOCKET_MAX_NUM; ++j)
|
|
|
|
|
if (item2->GetSocket(j) != item->GetSocket(j))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (j != ITEM_SOCKET_MAX_NUM)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
BYTE bCount2 = MIN(200 - item2->GetCount(), bCount);
|
|
|
|
|
bCount -= bCount2;
|
|
|
|
|
|
|
|
|
|
item2->SetCount(item2->GetCount() + bCount2);
|
|
|
|
|
|
|
|
|
|
if (bCount == 0)
|
|
|
|
|
{
|
|
|
|
|
ItemGetPacket(item2->GetVnum(), item2->GetCount());
|
|
|
|
|
M2_DESTROY_ITEM(item);
|
|
|
|
|
if (item2->GetType() == ITEM_QUEST)
|
|
|
|
|
quest::CQuestManager::instance().PickupItem (GetPlayerID(), item2);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
ItemGetPacket(item2->GetVnum(), item2->GetCount());
|
|
|
|
|
M2_DESTROY_ITEM(item);
|
|
|
|
|
if (item2->GetType() == ITEM_QUEST)
|
|
|
|
|
quest::CQuestManager::instance().PickupItem (GetPlayerID(), item2);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
item->SetCount(bCount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int iEmptyCell;
|
|
|
|
|
if (item->IsDragonSoul())
|
|
|
|
|
{
|
|
|
|
|
if ((iEmptyCell = GetEmptyDragonSoulInventory(item)) == -1)
|
|
|
|
|
{
|
|
|
|
|
sys_log(0, "No empty ds inventory pid %u size %ud itemid %u", GetPlayerID(), item->GetSize(), item->GetID());
|
|
|
|
|
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("소지하고 있는 아이템이 너무 많습니다."));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if ((iEmptyCell = GetEmptyInventory(item->GetSize())) == -1)
|
|
|
|
|
{
|
|
|
|
|
sys_log(0, "No empty inventory pid %u size %ud itemid %u", GetPlayerID(), item->GetSize(), item->GetID());
|
|
|
|
|
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("소지하고 있는 아이템이 너무 많습니다."));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
item->RemoveFromGround();
|
|
|
|
|
|
|
|
|
|
if (item->IsDragonSoul())
|
|
|
|
|
item->AddToCharacter(this, TItemPos(DRAGON_SOUL_INVENTORY, iEmptyCell));
|
|
|
|
|
else
|
|
|
|
|
item->AddToCharacter(this, TItemPos(INVENTORY, iEmptyCell));
|
|
|
|
|
|
|
|
|
|
char szHint[32+1];
|
|
|
|
|
snprintf(szHint, sizeof(szHint), "%s %u %u", item->GetName(), item->GetCount(), item->GetOriginalVnum());
|
|
|
|
|
LogManager::instance().ItemLog(this, item, "GET", szHint);
|
|
|
|
|
ItemGetPacket(item->GetVnum(), item->GetCount());
|
|
|
|
|
|
|
|
|
|
if (item->GetType() == ITEM_QUEST)
|
|
|
|
|
quest::CQuestManager::instance().PickupItem (GetPlayerID(), item);
|
|
|
|
|
item->SetCount(bCount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Motion(MOTION_PICKUP);
|
|
|
|
|
return true;
|
|
|
|
|
int iEmptyCell;
|
|
|
|
|
if (item->IsDragonSoul())
|
|
|
|
|
{
|
|
|
|
|
if ((iEmptyCell = GetEmptyDragonSoulInventory(item)) == -1)
|
|
|
|
|
{
|
|
|
|
|
sys_log(0, "No empty ds inventory pid %u size %ud itemid %u", GetPlayerID(), item->GetSize(), item->GetID());
|
|
|
|
|
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("소지하고 있는 아이템이 너무 많습니다."));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if ((iEmptyCell = GetEmptyInventory(item->GetSize())) == -1)
|
|
|
|
|
{
|
|
|
|
|
sys_log(0, "No empty inventory pid %u size %ud itemid %u", GetPlayerID(), item->GetSize(), item->GetID());
|
|
|
|
|
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("소지하고 있는 아이템이 너무 많습니다."));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
item->RemoveFromGround();
|
|
|
|
|
|
|
|
|
|
if (item->IsDragonSoul())
|
|
|
|
|
item->AddToCharacter(this, TItemPos(DRAGON_SOUL_INVENTORY, iEmptyCell));
|
|
|
|
|
else
|
|
|
|
|
item->AddToCharacter(this, TItemPos(INVENTORY, iEmptyCell));
|
|
|
|
|
|
|
|
|
|
char szHint[32+1];
|
|
|
|
|
snprintf(szHint, sizeof(szHint), "%s %u %u", item->GetName(), item->GetCount(), item->GetOriginalVnum());
|
|
|
|
|
LogManager::instance().ItemLog(this, item, "GET", szHint);
|
|
|
|
|
ItemGetPacket(item->GetVnum(), item->GetCount());
|
|
|
|
|
|
|
|
|
|
if (item->GetType() == ITEM_QUEST)
|
|
|
|
|
quest::CQuestManager::instance().PickupItem (GetPlayerID(), item);
|
|
|
|
|
}
|
|
|
|
|
else if (!IS_SET(item->GetAntiFlag(), ITEM_ANTIFLAG_GIVE | ITEM_ANTIFLAG_DROP) && GetParty())
|
|
|
|
|
|
|
|
|
|
//Motion(MOTION_PICKUP);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else if (item->HasOwnership())
|
|
|
|
|
{
|
|
|
|
|
if (!IS_SET(item->GetAntiFlag(), ITEM_ANTIFLAG_GIVE | ITEM_ANTIFLAG_DROP) && GetParty())
|
|
|
|
|
{
|
|
|
|
|
// 다른 파티원 소유권 아이템을 주으려고 한다면
|
|
|
|
|
NPartyPickupDistribute::FFindOwnership funcFindOwnership(item);
|
|
|
|
|
@@ -5955,11 +5988,19 @@ bool CHARACTER::PickupItem(DWORD dwVID)
|
|
|
|
|
|
|
|
|
|
LPCHARACTER owner = funcFindOwnership.owner;
|
|
|
|
|
|
|
|
|
|
if (!owner)
|
|
|
|
|
{
|
|
|
|
|
char szDetail[160];
|
|
|
|
|
snprintf(szDetail, sizeof(szDetail), "item=%u owner_pid=%u party=%d", item->GetVID(), item->GetOwnershipPID(), GetParty() ? 1 : 0);
|
|
|
|
|
RecordAntiCheatViolation("PICKUP_OWNERSHIP", 6, szDetail, true);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int iEmptyCell;
|
|
|
|
|
|
|
|
|
|
if (item->IsDragonSoul())
|
|
|
|
|
{
|
|
|
|
|
if (!(owner && (iEmptyCell = owner->GetEmptyDragonSoulInventory(item)) != -1))
|
|
|
|
|
if ((iEmptyCell = owner->GetEmptyDragonSoulInventory(item)) == -1)
|
|
|
|
|
{
|
|
|
|
|
owner = this;
|
|
|
|
|
|
|
|
|
|
@@ -5972,7 +6013,7 @@ bool CHARACTER::PickupItem(DWORD dwVID)
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (!(owner && (iEmptyCell = owner->GetEmptyInventory(item->GetSize())) != -1))
|
|
|
|
|
if ((iEmptyCell = owner->GetEmptyInventory(item->GetSize())) == -1)
|
|
|
|
|
{
|
|
|
|
|
owner = this;
|
|
|
|
|
|
|
|
|
|
@@ -6008,6 +6049,10 @@ bool CHARACTER::PickupItem(DWORD dwVID)
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char szDetail[160];
|
|
|
|
|
snprintf(szDetail, sizeof(szDetail), "item=%u owner_pid=%u party=%d", item->GetVID(), item->GetOwnershipPID(), GetParty() ? 1 : 0);
|
|
|
|
|
RecordAntiCheatViolation("PICKUP_OWNERSHIP", 4, szDetail);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|