1
0
forked from metin2/server
server/game/src/item_attribute.cpp
2022-03-05 12:44:06 +02:00

422 lines
7.8 KiB
C++

#include "stdafx.h"
#include "constants.h"
#include "log.h"
#include "item.h"
#include "char.h"
#include "desc.h"
#include "item_manager.h"
const int MAX_NORM_ATTR_NUM = ITEM_MANAGER::MAX_NORM_ATTR_NUM;
const int MAX_RARE_ATTR_NUM = ITEM_MANAGER::MAX_RARE_ATTR_NUM;
int CItem::GetAttributeSetIndex()
{
if (GetType() == ITEM_WEAPON)
{
if (GetSubType() == WEAPON_ARROW)
return -1;
return ATTRIBUTE_SET_WEAPON;
}
if (GetType() == ITEM_ARMOR || GetType() == ITEM_COSTUME)
{
switch (GetSubType())
{
case ARMOR_BODY:
// case COSTUME_BODY: // 코스츔 갑옷은 일반 갑옷과 동일한 Attribute Set을 이용하여 랜덤속성 붙음 (ARMOR_BODY == COSTUME_BODY)
return ATTRIBUTE_SET_BODY;
case ARMOR_WRIST:
return ATTRIBUTE_SET_WRIST;
case ARMOR_FOOTS:
return ATTRIBUTE_SET_FOOTS;
case ARMOR_NECK:
return ATTRIBUTE_SET_NECK;
case ARMOR_HEAD:
// case COSTUME_HAIR: // 코스츔 헤어는 일반 투구 아이템과 동일한 Attribute Set을 이용하여 랜덤속성 붙음 (ARMOR_HEAD == COSTUME_HAIR)
return ATTRIBUTE_SET_HEAD;
case ARMOR_SHIELD:
return ATTRIBUTE_SET_SHIELD;
case ARMOR_EAR:
return ATTRIBUTE_SET_EAR;
}
}
return -1;
}
bool CItem::HasAttr(BYTE bApply)
{
for (int i = 0; i < ITEM_APPLY_MAX_NUM; ++i)
if (m_pProto->aApplies[i].bType == bApply)
return true;
for (int i = 0; i < MAX_NORM_ATTR_NUM; ++i)
if (GetAttributeType(i) == bApply)
return true;
return false;
}
bool CItem::HasRareAttr(BYTE bApply)
{
for (int i = 0; i < MAX_RARE_ATTR_NUM; ++i)
if (GetAttributeType(i + 5) == bApply)
return true;
return false;
}
void CItem::AddAttribute(BYTE bApply, short sValue)
{
if (HasAttr(bApply))
return;
int i = GetAttributeCount();
if (i >= MAX_NORM_ATTR_NUM)
sys_err("item attribute overflow!");
else
{
if (sValue)
SetAttribute(i, bApply, sValue);
}
}
void CItem::AddAttr(BYTE bApply, BYTE bLevel)
{
if (HasAttr(bApply))
return;
if (bLevel <= 0)
return;
int i = GetAttributeCount();
if (i == MAX_NORM_ATTR_NUM)
sys_err("item attribute overflow!");
else
{
const TItemAttrTable & r = g_map_itemAttr[bApply];
long lVal = r.lValues[MIN(4, bLevel - 1)];
if (lVal)
SetAttribute(i, bApply, lVal);
}
}
void CItem::PutAttributeWithLevel(BYTE bLevel)
{
int iAttributeSet = GetAttributeSetIndex();
if (iAttributeSet < 0)
return;
if (bLevel > ITEM_ATTRIBUTE_MAX_LEVEL)
return;
std::vector<int> avail;
int total = 0;
// 붙일 수 있는 속성 배열을 구축
for (int i = 0; i < MAX_APPLY_NUM; ++i)
{
const TItemAttrTable & r = g_map_itemAttr[i];
if (r.bMaxLevelBySet[iAttributeSet] && !HasAttr(i))
{
avail.push_back(i);
total += r.dwProb;
}
}
// 구축된 배열로 확률 계산을 통해 붙일 속성 선정
unsigned int prob = number(1, total);
int attr_idx = APPLY_NONE;
for (DWORD i = 0; i < avail.size(); ++i)
{
const TItemAttrTable & r = g_map_itemAttr[avail[i]];
if (prob <= r.dwProb)
{
attr_idx = avail[i];
break;
}
prob -= r.dwProb;
}
if (!attr_idx)
{
sys_err("Cannot put item attribute %d %d", iAttributeSet, bLevel);
return;
}
const TItemAttrTable & r = g_map_itemAttr[attr_idx];
// 종류별 속성 레벨 최대값 제한
if (bLevel > r.bMaxLevelBySet[iAttributeSet])
bLevel = r.bMaxLevelBySet[iAttributeSet];
AddAttr(attr_idx, bLevel);
}
void CItem::PutAttribute(const int * aiAttrPercentTable)
{
int iAttrLevelPercent = number(1, 100);
int i;
for (i = 0; i < ITEM_ATTRIBUTE_MAX_LEVEL; ++i)
{
if (iAttrLevelPercent <= aiAttrPercentTable[i])
break;
iAttrLevelPercent -= aiAttrPercentTable[i];
}
PutAttributeWithLevel(i + 1);
}
void CItem::ChangeAttribute(const int* aiChangeProb)
{
int iAttributeCount = GetAttributeCount();
ClearAttribute();
if (iAttributeCount == 0)
return;
TItemTable const * pProto = GetProto();
if (pProto && pProto->sAddonType)
{
ApplyAddon(pProto->sAddonType);
}
static const int tmpChangeProb[ITEM_ATTRIBUTE_MAX_LEVEL] =
{
0, 10, 40, 35, 15,
};
for (int i = GetAttributeCount(); i < iAttributeCount; ++i)
{
if (aiChangeProb == NULL)
{
PutAttribute(tmpChangeProb);
}
else
{
PutAttribute(aiChangeProb);
}
}
}
void CItem::AddAttribute()
{
static const int aiItemAddAttributePercent[ITEM_ATTRIBUTE_MAX_LEVEL] =
{
40, 50, 10, 0, 0
};
if (GetAttributeCount() < MAX_NORM_ATTR_NUM)
PutAttribute(aiItemAddAttributePercent);
}
void CItem::ClearAttribute()
{
for (int i = 0; i < MAX_NORM_ATTR_NUM; ++i)
{
m_aAttr[i].bType = 0;
m_aAttr[i].sValue = 0;
}
}
int CItem::GetAttributeCount()
{
int i;
for (i = 0; i < MAX_NORM_ATTR_NUM; ++i)
{
if (GetAttributeType(i) == 0)
break;
}
return i;
}
int CItem::FindAttribute(BYTE bType)
{
for (int i = 0; i < MAX_NORM_ATTR_NUM; ++i)
{
if (GetAttributeType(i) == bType)
return i;
}
return -1;
}
bool CItem::RemoveAttributeAt(int index)
{
if (GetAttributeCount() <= index)
return false;
for (int i = index; i < MAX_NORM_ATTR_NUM - 1; ++i)
{
SetAttribute(i, GetAttributeType(i + 1), GetAttributeValue(i + 1));
}
SetAttribute(MAX_NORM_ATTR_NUM - 1, APPLY_NONE, 0);
return true;
}
bool CItem::RemoveAttributeType(BYTE bType)
{
int index = FindAttribute(bType);
return index != -1 && RemoveAttributeType(index);
}
void CItem::SetAttributes(const TPlayerItemAttribute* c_pAttribute)
{
thecore_memcpy(m_aAttr, c_pAttribute, sizeof(m_aAttr));
Save();
}
void CItem::SetAttribute(int i, BYTE bType, short sValue)
{
assert(i < MAX_NORM_ATTR_NUM);
m_aAttr[i].bType = bType;
m_aAttr[i].sValue = sValue;
UpdatePacket();
Save();
if (bType)
{
const char * pszIP = NULL;
if (GetOwner() && GetOwner()->GetDesc())
pszIP = GetOwner()->GetDesc()->GetHostName();
LogManager::instance().ItemLog(i, bType, sValue, GetID(), "SET_ATTR", "", pszIP ? pszIP : "", GetOriginalVnum());
}
}
void CItem::SetForceAttribute(int i, BYTE bType, short sValue)
{
assert(i < ITEM_ATTRIBUTE_MAX_NUM);
m_aAttr[i].bType = bType;
m_aAttr[i].sValue = sValue;
UpdatePacket();
Save();
if (bType)
{
const char * pszIP = NULL;
if (GetOwner() && GetOwner()->GetDesc())
pszIP = GetOwner()->GetDesc()->GetHostName();
LogManager::instance().ItemLog(i, bType, sValue, GetID(), "SET_FORCE_ATTR", "", pszIP ? pszIP : "", GetOriginalVnum());
}
}
void CItem::CopyAttributeTo(LPITEM pItem)
{
pItem->SetAttributes(m_aAttr);
}
int CItem::GetRareAttrCount()
{
int ret = 0;
if (m_aAttr[5].bType != 0)
ret++;
if (m_aAttr[6].bType != 0)
ret++;
return ret;
}
bool CItem::ChangeRareAttribute()
{
if (GetRareAttrCount() == 0)
return false;
int cnt = GetRareAttrCount();
for (int i = 0; i < cnt; ++i)
{
m_aAttr[i + 5].bType = 0;
m_aAttr[i + 5].sValue = 0;
}
if (GetOwner() && GetOwner()->GetDesc())
LogManager::instance().ItemLog(GetOwner(), this, "SET_RARE_CHANGE", "");
else
LogManager::instance().ItemLog(0, 0, 0, GetID(), "SET_RARE_CHANGE", "", "", GetOriginalVnum());
for (int i = 0; i < cnt; ++i)
{
AddRareAttribute();
}
return true;
}
bool CItem::AddRareAttribute()
{
int count = GetRareAttrCount();
if (count >= 2)
return false;
int pos = count + 5;
TPlayerItemAttribute & attr = m_aAttr[pos];
int nAttrSet = GetAttributeSetIndex();
std::vector<int> avail;
for (int i = 0; i < MAX_APPLY_NUM; ++i)
{
const TItemAttrTable & r = g_map_itemRare[i];
if (r.dwApplyIndex != 0 && r.bMaxLevelBySet[nAttrSet] > 0 && HasRareAttr(i) != true)
{
avail.push_back(i);
}
}
const TItemAttrTable& r = g_map_itemRare[avail[number(0, avail.size() - 1)]];
int nAttrLevel = 5;
if (nAttrLevel > r.bMaxLevelBySet[nAttrSet])
nAttrLevel = r.bMaxLevelBySet[nAttrSet];
attr.bType = r.dwApplyIndex;
attr.sValue = r.lValues[nAttrLevel - 1];
UpdatePacket();
Save();
const char * pszIP = NULL;
if (GetOwner() && GetOwner()->GetDesc())
pszIP = GetOwner()->GetDesc()->GetHostName();
LogManager::instance().ItemLog(pos, attr.bType, attr.sValue, GetID(), "SET_RARE", "", pszIP ? pszIP : "", GetOriginalVnum());
return true;
}