forked from metin2/server
332 lines
9.5 KiB
C++
332 lines
9.5 KiB
C++
#ifndef __INC_METIN_II_GAME_ITEM_H__
|
|
#define __INC_METIN_II_GAME_ITEM_H__
|
|
|
|
#include "entity.h"
|
|
|
|
class CItem : public CEntity
|
|
{
|
|
protected:
|
|
// override methods from ENTITY class
|
|
virtual void EncodeInsertPacket(LPENTITY entity);
|
|
virtual void EncodeRemovePacket(LPENTITY entity);
|
|
|
|
public:
|
|
CItem(DWORD dwVnum);
|
|
virtual ~CItem();
|
|
|
|
int GetLevelLimit();
|
|
|
|
bool CheckItemUseLevel(int nLevel);
|
|
|
|
bool IsPCBangItem();
|
|
|
|
int FindApplyValue(BYTE bApplyType);
|
|
|
|
bool IsStackable() { return (GetFlag() & ITEM_FLAG_STACKABLE)?true:false; }
|
|
|
|
void Initialize();
|
|
void Destroy();
|
|
|
|
void Save();
|
|
|
|
void SetWindow(BYTE b) { m_bWindow = b; }
|
|
BYTE GetWindow() { return m_bWindow; }
|
|
|
|
void SetID(DWORD id) { m_dwID = id; }
|
|
DWORD GetID() { return m_dwID; }
|
|
|
|
void SetProto(const TItemTable * table);
|
|
TItemTable const * GetProto() { return m_pProto; }
|
|
|
|
int GetGold();
|
|
int GetShopBuyPrice();
|
|
const char * GetName() { return m_pProto ? m_pProto->szLocaleName : NULL; }
|
|
const char * GetBaseName() { return m_pProto ? m_pProto->szName : NULL; }
|
|
BYTE GetSize() { return m_pProto ? m_pProto->bSize : 0; }
|
|
|
|
void SetFlag(int flag) { m_lFlag = flag; }
|
|
int GetFlag() { return m_lFlag; }
|
|
|
|
void AddFlag(int bit);
|
|
void RemoveFlag(int bit);
|
|
|
|
DWORD GetWearFlag() { return m_pProto ? m_pProto->dwWearFlags : 0; }
|
|
DWORD GetAntiFlag() { return m_pProto ? m_pProto->dwAntiFlags : 0; }
|
|
DWORD GetImmuneFlag() { return m_pProto ? m_pProto->dwImmuneFlag : 0; }
|
|
|
|
void SetVID(DWORD vid) { m_dwVID = vid; }
|
|
DWORD GetVID() { return m_dwVID; }
|
|
|
|
bool SetCount(DWORD count);
|
|
DWORD GetCount();
|
|
|
|
// GetVnum과 GetOriginalVnum에 대한 comment
|
|
// GetVnum은 Masking 된 Vnum이다. 이를 사용함으로써, 아이템의 실제 Vnum은 10이지만, Vnum이 20인 것처럼 동작할 수 있는 것이다.
|
|
// Masking 값은 ori_to_new.txt에서 정의된 값이다.
|
|
// GetOriginalVnum은 아이템 고유의 Vnum으로, 로그 남길 때, 클라이언트에 아이템 정보 보낼 때, 저장할 때는 이 Vnum을 사용하여야 한다.
|
|
//
|
|
DWORD GetVnum() const { return m_dwMaskVnum ? m_dwMaskVnum : m_dwVnum; }
|
|
DWORD GetOriginalVnum() const { return m_dwVnum; }
|
|
BYTE GetType() const { return m_pProto ? m_pProto->bType : 0; }
|
|
BYTE GetSubType() const { return m_pProto ? m_pProto->bSubType : 0; }
|
|
BYTE GetLimitType(DWORD idx) const { return m_pProto ? m_pProto->aLimits[idx].bType : 0; }
|
|
int GetLimitValue(DWORD idx) const { return m_pProto ? m_pProto->aLimits[idx].lValue : 0; }
|
|
|
|
int GetValue(DWORD idx);
|
|
|
|
void SetCell(LPCHARACTER ch, WORD pos) { m_pOwner = ch, m_wCell = pos; }
|
|
WORD GetCell() { return m_wCell; }
|
|
|
|
LPITEM RemoveFromCharacter();
|
|
bool AddToCharacter(LPCHARACTER ch, TItemPos Cell);
|
|
LPCHARACTER GetOwner() { return m_pOwner; }
|
|
|
|
LPITEM RemoveFromGround();
|
|
bool AddToGround(int lMapIndex, const PIXEL_POSITION & pos, bool skipOwnerCheck = false);
|
|
|
|
int FindEquipCell(LPCHARACTER ch, int bCandidateCell = -1);
|
|
bool IsEquipped() const { return m_bEquipped; }
|
|
bool EquipTo(LPCHARACTER ch, BYTE bWearCell);
|
|
bool IsEquipable() const;
|
|
|
|
bool CanUsedBy(LPCHARACTER ch);
|
|
|
|
bool DistanceValid(LPCHARACTER ch);
|
|
|
|
void UpdatePacket();
|
|
void UsePacketEncode(LPCHARACTER ch, LPCHARACTER victim, struct packet_item_use * packet);
|
|
|
|
void SetExchanging(bool isOn = true);
|
|
bool IsExchanging() { return m_bExchanging; }
|
|
|
|
bool IsTwohanded();
|
|
|
|
bool IsPolymorphItem();
|
|
|
|
void ModifyPoints(bool bAdd); // 아이템의 효과를 캐릭터에 부여 한다. bAdd가 false이면 제거함
|
|
|
|
bool CreateSocket(BYTE bSlot, BYTE bGold);
|
|
const int * GetSockets() { return &m_alSockets[0]; }
|
|
int GetSocket(int i) { return m_alSockets[i]; }
|
|
|
|
void SetSockets(const LONG * al);
|
|
void SetSocket(int i, int v, bool bLog = true);
|
|
|
|
int GetSocketCount();
|
|
bool AddSocket();
|
|
|
|
const TPlayerItemAttribute* GetAttributes() { return m_aAttr; }
|
|
const TPlayerItemAttribute& GetAttribute(int i) { return m_aAttr[i]; }
|
|
|
|
BYTE GetAttributeType(int i) { return m_aAttr[i].bType; }
|
|
short GetAttributeValue(int i){ return m_aAttr[i].sValue; }
|
|
|
|
void SetAttributes(const TPlayerItemAttribute* c_pAttribute);
|
|
|
|
int FindAttribute(BYTE bType);
|
|
bool RemoveAttributeAt(int index);
|
|
bool RemoveAttributeType(BYTE bType);
|
|
|
|
bool HasAttr(BYTE bApply);
|
|
bool HasRareAttr(BYTE bApply);
|
|
|
|
void SetDestroyEvent(LPEVENT pkEvent);
|
|
void StartDestroyEvent(int iSec=300);
|
|
|
|
DWORD GetRefinedVnum() { return m_pProto ? m_pProto->dwRefinedVnum : 0; }
|
|
DWORD GetRefineFromVnum();
|
|
int GetRefineLevel();
|
|
|
|
void SetSkipSave(bool b) { m_bSkipSave = b; }
|
|
bool GetSkipSave() { return m_bSkipSave; }
|
|
|
|
bool IsOwnership(LPCHARACTER ch);
|
|
void SetOwnership(LPCHARACTER ch, int iSec = 10);
|
|
void SetOwnershipEvent(LPEVENT pkEvent);
|
|
|
|
DWORD GetLastOwnerPID() { return m_dwLastOwnerPID; }
|
|
|
|
int GetAttributeSetIndex(); // 속성 붙는것을 지정한 배열의 어느 인덱스를 사용하는지 돌려준다.
|
|
void AlterToMagicItem();
|
|
void AlterToSocketItem(int iSocketCount);
|
|
|
|
WORD GetRefineSet() { return m_pProto ? m_pProto->wRefineSet : 0; }
|
|
|
|
void StartUniqueExpireEvent();
|
|
void SetUniqueExpireEvent(LPEVENT pkEvent);
|
|
|
|
void StartTimerBasedOnWearExpireEvent();
|
|
void SetTimerBasedOnWearExpireEvent(LPEVENT pkEvent);
|
|
|
|
void StartRealTimeExpireEvent();
|
|
bool IsRealTimeItem();
|
|
|
|
void StopUniqueExpireEvent();
|
|
void StopTimerBasedOnWearExpireEvent();
|
|
void StopAccessorySocketExpireEvent();
|
|
|
|
// 일단 REAL_TIME과 TIMER_BASED_ON_WEAR 아이템에 대해서만 제대로 동작함.
|
|
int GetDuration();
|
|
|
|
int GetAttributeCount();
|
|
void ClearAttribute();
|
|
void ChangeAttribute(const int* aiChangeProb=NULL);
|
|
void AddAttribute();
|
|
void AddAttribute(BYTE bType, short sValue);
|
|
|
|
void ApplyAddon(int iAddonType);
|
|
|
|
int GetSpecialGroup() const;
|
|
bool IsSameSpecialGroup(const LPITEM item) const;
|
|
|
|
// ACCESSORY_REFINE
|
|
// 액세서리에 광산을 통해 소켓을 추가
|
|
bool IsAccessoryForSocket();
|
|
|
|
int GetAccessorySocketGrade();
|
|
int GetAccessorySocketMaxGrade();
|
|
int GetAccessorySocketDownGradeTime();
|
|
|
|
void SetAccessorySocketGrade(int iGrade);
|
|
void SetAccessorySocketMaxGrade(int iMaxGrade);
|
|
void SetAccessorySocketDownGradeTime(DWORD time);
|
|
|
|
void AccessorySocketDegrade();
|
|
|
|
// 악세사리 를 아이템에 밖았을때 타이머 돌아가는것( 구리, 등 )
|
|
void StartAccessorySocketExpireEvent();
|
|
void SetAccessorySocketExpireEvent(LPEVENT pkEvent);
|
|
|
|
bool CanPutInto(LPITEM item);
|
|
// END_OF_ACCESSORY_REFINE
|
|
|
|
void CopyAttributeTo(LPITEM pItem);
|
|
void CopySocketTo(LPITEM pItem);
|
|
|
|
int GetRareAttrCount();
|
|
bool AddRareAttribute();
|
|
bool ChangeRareAttribute();
|
|
|
|
void AttrLog();
|
|
|
|
void Lock(bool f) { m_isLocked = f; }
|
|
bool isLocked() const { return m_isLocked; }
|
|
|
|
private :
|
|
void SetAttribute(int i, BYTE bType, short sValue);
|
|
public:
|
|
void SetForceAttribute(int i, BYTE bType, short sValue);
|
|
|
|
protected:
|
|
bool EquipEx(bool is_equip);
|
|
bool Unequip();
|
|
|
|
void AddAttr(BYTE bApply, BYTE bLevel);
|
|
void PutAttribute(const int * aiAttrPercentTable);
|
|
void PutAttributeWithLevel(BYTE bLevel);
|
|
|
|
protected:
|
|
friend class CInputDB;
|
|
bool OnAfterCreatedItem(); // 서버상에 아이템이 모든 정보와 함께 완전히 생성(로드)된 후 불리우는 함수.
|
|
|
|
public:
|
|
bool IsRideItem();
|
|
bool IsRamadanRing();
|
|
|
|
void ClearMountAttributeAndAffect();
|
|
bool IsNewMountItem();
|
|
|
|
#ifdef __AUCTION__
|
|
// 경매장
|
|
bool MoveToAuction ();
|
|
void CopyToRawData (TPlayerItem* item);
|
|
#endif
|
|
// 독일에서 기존 캐시 아이템과 같지만, 교환 가능한 캐시 아이템을 만든다고 하여,
|
|
// 오리지널 아이템에, 교환 금지 플래그만 삭제한 새로운 아이템들을 새로운 아이템 대역에 할당하였다.
|
|
// 문제는 새로운 아이템도 오리지널 아이템과 같은 효과를 내야하는데,
|
|
// 서버건, 클라건, vnum 기반으로 되어있어
|
|
// 새로운 vnum을 죄다 서버에 새로 다 박아야하는 안타까운 상황에 맞닿았다.
|
|
// 그래서 새 vnum의 아이템이면, 서버에서 돌아갈 때는 오리지널 아이템 vnum으로 바꿔서 돌고 하고,
|
|
// 저장할 때에 본래 vnum으로 바꿔주도록 한다.
|
|
|
|
// Mask vnum은 어떤 이유(ex. 위의 상황)로 인해 vnum이 바뀌어 돌아가는 아이템을 위해 있다.
|
|
void SetMaskVnum(DWORD vnum) { m_dwMaskVnum = vnum; }
|
|
DWORD GetMaskVnum() { return m_dwMaskVnum; }
|
|
bool IsMaskedItem() { return m_dwMaskVnum != 0; }
|
|
|
|
// 용혼석
|
|
bool IsDragonSoul();
|
|
int GiveMoreTime_Per(float fPercent);
|
|
int GiveMoreTime_Fix(DWORD dwTime);
|
|
|
|
private:
|
|
TItemTable const * m_pProto; // 프로토 타잎
|
|
|
|
DWORD m_dwVnum;
|
|
LPCHARACTER m_pOwner;
|
|
|
|
BYTE m_bWindow; // 현재 아이템이 위치한 윈도우
|
|
DWORD m_dwID; // 고유번호
|
|
bool m_bEquipped; // 장착 되었는가?
|
|
DWORD m_dwVID; // VID
|
|
WORD m_wCell; // 위치
|
|
DWORD m_dwCount; // 개수
|
|
int m_lFlag; // 추가 flag
|
|
DWORD m_dwLastOwnerPID; // 마지막 가지고 있었던 사람의 PID
|
|
|
|
bool m_bExchanging; ///< 현재 교환중 상태
|
|
|
|
int m_alSockets[ITEM_SOCKET_MAX_NUM]; // 아이템 소캣
|
|
TPlayerItemAttribute m_aAttr[ITEM_ATTRIBUTE_MAX_NUM];
|
|
|
|
LPEVENT m_pkDestroyEvent;
|
|
LPEVENT m_pkExpireEvent;
|
|
LPEVENT m_pkUniqueExpireEvent;
|
|
LPEVENT m_pkTimerBasedOnWearExpireEvent;
|
|
LPEVENT m_pkRealTimeExpireEvent;
|
|
LPEVENT m_pkAccessorySocketExpireEvent;
|
|
LPEVENT m_pkOwnershipEvent;
|
|
|
|
DWORD m_dwOwnershipPID;
|
|
|
|
bool m_bSkipSave;
|
|
|
|
bool m_isLocked;
|
|
|
|
DWORD m_dwMaskVnum;
|
|
DWORD m_dwSIGVnum;
|
|
public:
|
|
void SetSIGVnum(DWORD dwSIG)
|
|
{
|
|
m_dwSIGVnum = dwSIG;
|
|
}
|
|
DWORD GetSIGVnum() const
|
|
{
|
|
return m_dwSIGVnum;
|
|
}
|
|
};
|
|
|
|
EVENTINFO(item_event_info)
|
|
{
|
|
LPITEM item;
|
|
char szOwnerName[CHARACTER_NAME_MAX_LEN];
|
|
|
|
item_event_info()
|
|
: item( 0 )
|
|
{
|
|
::memset( szOwnerName, 0, CHARACTER_NAME_MAX_LEN );
|
|
}
|
|
};
|
|
|
|
EVENTINFO(item_vid_event_info)
|
|
{
|
|
DWORD item_vid;
|
|
|
|
item_vid_event_info()
|
|
: item_vid( 0 )
|
|
{
|
|
}
|
|
};
|
|
|
|
#endif
|