-
Posts
260 -
Joined
-
Last visited
-
Days Won
2 -
Feedback
0%
Content Type
Forums
Store
Third Party - Providers Directory
Feature Plan
Release Notes
Docs
Events
Posts posted by displayjokes
-
-
Hey, has the title says, i summon a pet or a mount and both of them won't follow me around, if i get far enough they will teleport to me but never walk/run in my direction
Any idea on what's causing this?
Thanks in advance
-
5 hours ago, newhere said:
Hey, i have problem with Sash.
Its absorbing the 100% of the 1/5 and 6/7 Bonus.
Like in this Thread. But i dont know what/how to change in item.cpp maybe you can help me.
Is it here?
attrVal = int(float(attrVal) / 100.0f * float(GetSocket(0)));// <= 0 ? 1 : int(float(attrVal) / 100.0f * float(GetSocket(0)));
item.cpp full:
#include "stdafx.h"
#include "utils.h"
#include "config.h"
#include "char.h"
#include "desc.h"
#include "sectree_manager.h"
#include "packet.h"
#include "mob_manager.h"
#include "protocol.h"
#include "log.h"
#include "skill.h"
#include "unique_item.h"
#include "profiler.h"
#include "marriage.h"
#include "item_addon.h"
#include "dev_log.h"
#include "locale_service.h"
#include "item.h"
#include "item_manager.h"
#include "affect.h"
#include "DragonSoul.h"
#include "buff_on_attributes.h"
#include "belt_inventory_helper.h"
#ifdef SHOP_SEARCH
#include "shop_search.h"
#endif
#include "../../common/VnumHelper.h"
#include "../../common/CommonDefines.h"CItem::CItem(DWORD dwVnum)
: m_dwVnum(dwVnum), m_bWindow(0), m_dwID(0), m_bEquipped(false), m_dwVID(0), m_wCell(0), m_dwCount(0), m_lFlag(0), m_dwLastOwnerPID(0),
m_bExchanging(false), m_pkDestroyEvent(NULL), m_pkExpireEvent(NULL), m_pkUniqueExpireEvent(NULL),
m_pkTimerBasedOnWearExpireEvent(NULL), m_pkRealTimeExpireEvent(NULL),
m_pkAccessorySocketExpireEvent(NULL), m_pkOwnershipEvent(NULL), m_dwOwnershipPID(0), m_bSkipSave(false), m_isLocked(false),
m_dwMaskVnum(0), m_dwSIGVnum (0)
#ifdef __CHANGE_LOOK_SYSTEM__
, m_dwLook(0)
#endif
{
memset( &m_alSockets, 0, sizeof(m_alSockets) );
memset( &m_aAttr, 0, sizeof(m_aAttr) );
}CItem::~CItem()
{
Destroy();
}void CItem::Initialize()
{
CEntity::Initialize(ENTITY_ITEM);m_bWindow = RESERVED_WINDOW;
m_pOwner = NULL;
m_dwID = 0;
m_bEquipped = false;
m_dwVID = m_wCell = m_dwCount = m_lFlag = 0;
m_pProto = NULL;
m_bExchanging = false;
memset(&m_alSockets, 0, sizeof(m_alSockets));
memset(&m_aAttr, 0, sizeof(m_aAttr));m_pkDestroyEvent = NULL;
m_pkOwnershipEvent = NULL;
m_dwOwnershipPID = 0;
m_pkUniqueExpireEvent = NULL;
m_pkTimerBasedOnWearExpireEvent = NULL;
m_pkRealTimeExpireEvent = NULL;m_pkAccessorySocketExpireEvent = NULL;
#ifdef OFFLINE_SHOP
m_dwRealID = 0;
#endif
m_bSkipSave = false;
m_dwLastOwnerPID = 0;
#ifdef __CHANGE_LOOK_SYSTEM__
m_dwLook = 0;
#endif
}void CItem::Destroy()
{
event_cancel(&m_pkDestroyEvent);
event_cancel(&m_pkOwnershipEvent);
event_cancel(&m_pkUniqueExpireEvent);
event_cancel(&m_pkTimerBasedOnWearExpireEvent);
event_cancel(&m_pkRealTimeExpireEvent);
event_cancel(&m_pkAccessorySocketExpireEvent);CEntity::Destroy();
if (GetSectree())
GetSectree()->RemoveEntity(this);
}EVENTFUNC(item_destroy_event)
{
item_event_info* info = dynamic_cast<item_event_info*>( event->info );if ( info == NULL )
{
sys_err( "item_destroy_event> <Factor> Null pointer" );
return 0;
}LPITEM pkItem = info->item;
if (pkItem->GetOwner())
sys_err("item_destroy_event: Owner exist. (item %s owner %s)", pkItem->GetName(), pkItem->GetOwner()->GetName());pkItem->SetDestroyEvent(NULL);
M2_DESTROY_ITEM(pkItem);
return 0;
}void CItem::SetDestroyEvent(LPEVENT pkEvent)
{
m_pkDestroyEvent = pkEvent;
}void CItem::StartDestroyEvent(int iSec)
{
if (m_pkDestroyEvent)
return;item_event_info* info = AllocEventInfo<item_event_info>();
info->item = this;SetDestroyEvent(event_create(item_destroy_event, info, PASSES_PER_SEC(iSec)));
}void CItem::EncodeInsertPacket(LPENTITY ent)
{
LPDESC d;if (!(d = ent->GetDesc()))
return;const PIXEL_POSITION & c_pos = GetXYZ();
struct packet_item_ground_add pack;
pack.bHeader = HEADER_GC_ITEM_GROUND_ADD;
pack.x = c_pos.x;
pack.y = c_pos.y;
pack.z = c_pos.z;
pack.dwVnum = GetVnum();
pack.dwVID = m_dwVID;
//pack.count = m_dwCount;
#ifdef ENABLE_EXTENDED_ITEMNAME_ON_GROUND
for (size_t i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
pack.alSockets = GetSocket(i);thecore_memcpy(pack.aAttrs, GetAttributes(), sizeof(pack.aAttrs));
#endifd->Packet(&pack, sizeof(pack));
if (m_pkOwnershipEvent != NULL)
{
item_event_info * info = dynamic_cast<item_event_info *>(m_pkOwnershipEvent->info);if ( info == NULL )
{
sys_err( "CItem::EncodeInsertPacket> <Factor> Null pointer" );
return;
}TPacketGCItemOwnership p;
p.bHeader = HEADER_GC_ITEM_OWNERSHIP;
p.dwVID = m_dwVID;
strlcpy(p.szName, info->szOwnerName, sizeof(p.szName));d->Packet(&p, sizeof(TPacketGCItemOwnership));
}
}void CItem::EncodeRemovePacket(LPENTITY ent)
{
LPDESC d;if (!(d = ent->GetDesc()))
return;struct packet_item_ground_del pack;
pack.bHeader = HEADER_GC_ITEM_GROUND_DEL;
pack.dwVID = m_dwVID;d->Packet(&pack, sizeof(pack));
sys_log(2, "Item::EncodeRemovePacket %s to %s", GetName(), ((LPCHARACTER) ent)->GetName());
}void CItem::SetProto(const TItemTable * table)
{
assert(table != NULL);
m_pProto = table;
SetFlag(m_pProto->dwFlags);
}#ifdef ENABLE_EXTENDED_ITEMNAME_ON_GROUND
const char * CItem::GetName()
{
static char szItemName[128];
memset(szItemName, 0, sizeof(szItemName));
if (GetProto())
{
int len = 0;
switch (GetType())
{
case ITEM_POLYMORPH:
{
const DWORD dwMobVnum = GetSocket(0);
const CMob* pMob = CMobManager::instance().Get(dwMobVnum);
if (pMob)
len = snprintf(szItemName, sizeof(szItemName), "%s", pMob->m_table.szLocaleName);break;
}
case ITEM_SKILLBOOK:
case ITEM_SKILLFORGET:
{
const DWORD dwSkillVnum = (GetVnum() == ITEM_SKILLBOOK_VNUM || GetVnum() == ITEM_SKILLFORGET_VNUM) ? GetSocket(0) : 0;
const CSkillProto* pSkill = (dwSkillVnum != 0) ? CSkillManager::instance().Get(dwSkillVnum) : NULL;
if (pSkill)
len = snprintf(szItemName, sizeof(szItemName), "%s", pSkill->szName);break;
}
}
len += snprintf(szItemName + len, sizeof(szItemName) - len, (len>0)?" %s":"%s", GetProto()->szLocaleName);
}return szItemName;
}
#endifvoid CItem::UsePacketEncode(LPCHARACTER ch, LPCHARACTER victim, struct packet_item_use *packet)
{
if (!GetVnum())
return;packet->header = HEADER_GC_ITEM_USE;
packet->ch_vid = ch->GetVID();
packet->victim_vid = victim->GetVID();
packet->Cell = TItemPos(GetWindow(), m_wCell);
packet->vnum = GetVnum();
}void CItem::RemoveFlag(long bit)
{
REMOVE_BIT(m_lFlag, bit);
}void CItem::AddFlag(long bit)
{
SET_BIT(m_lFlag, bit);
}void CItem::UpdatePacket()
{
if (!m_pOwner || !m_pOwner->GetDesc())
return;TPacketGCItemUpdate pack;
pack.header = HEADER_GC_ITEM_UPDATE;
pack.Cell = TItemPos(GetWindow(), m_wCell);
#ifdef __CHANGE_LOOK_SYSTEM__
pack.dwVnum = m_dwLook;
#endif
pack.count = m_dwCount;for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
pack.alSockets = m_alSockets;thecore_memcpy(pack.aAttr, GetAttributes(), sizeof(pack.aAttr));
sys_log(2, "UpdatePacket %s -> %s", GetName(), m_pOwner->GetName());
m_pOwner->GetDesc()->Packet(&pack, sizeof(pack));
}DWORD CItem::GetCount()
{
if (GetType() == ITEM_ELK) return MIN(m_dwCount, INT_MAX);
else
{
return MIN(m_dwCount, g_bItemCountLimit);
}
}bool CItem::SetCount(DWORD count)
{
if (GetType() == ITEM_ELK)
{
m_dwCount = MIN(count, INT_MAX);
}
else
{
m_dwCount = MIN(count, g_bItemCountLimit);
}if (count == 0 && m_pOwner)
{
if (GetSubType() == USE_ABILITY_UP || GetSubType() == USE_POTION || GetVnum() == 70020)
{
LPCHARACTER pOwner = GetOwner();
WORD wCell = GetCell();RemoveFromCharacter();
if (!IsDragonSoul())
{
LPITEM pItem = pOwner->FindSpecifyItem(GetVnum());if (NULL != pItem)
{
pOwner->ChainQuickslotItem(pItem, QUICKSLOT_TYPE_ITEM, wCell);
}
else
{
#ifdef ENABLE_5_INVENTORY
pOwner->SyncQuickslot(QUICKSLOT_TYPE_ITEM, wCell, 750);
#else
pOwner->SyncQuickslot(QUICKSLOT_TYPE_ITEM, wCell, 255);
#endif
}
}M2_DESTROY_ITEM(this);
}
else
{
if (!IsDragonSoul())
{
#ifdef ENABLE_5_INVENTORY
m_pOwner->SyncQuickslot(QUICKSLOT_TYPE_ITEM, m_wCell, 750);
#else
m_pOwner->SyncQuickslot(QUICKSLOT_TYPE_ITEM, m_wCell, 255);
#endif
}
M2_DESTROY_ITEM(RemoveFromCharacter());
}return false;
}UpdatePacket();
Save();
return true;
}LPITEM CItem::RemoveFromCharacter()
{
if (!m_pOwner)
{
sys_err("Item::RemoveFromCharacter owner null");
return (this);
}LPCHARACTER pOwner = m_pOwner;
if (m_bEquipped)
{
Unequip();
//pOwner->UpdatePacket();SetWindow(RESERVED_WINDOW);
Save();
return (this);
}
else
{
if (GetWindow() != SAFEBOX && GetWindow() != MALL)
{
if (IsDragonSoul())
{
if (m_wCell >= DRAGON_SOUL_INVENTORY_MAX_NUM)
sys_err("CItem::RemoveFromCharacter: pos >= DRAGON_SOUL_INVENTORY_MAX_NUM");
else
pOwner->SetItem(TItemPos(m_bWindow, m_wCell), NULL);
}
else
{
TItemPos cell(INVENTORY, m_wCell);if (false == cell.IsDefaultInventoryPosition() && false == cell.IsBeltInventoryPosition())
sys_err("CItem::RemoveFromCharacter: Invalid Item Position");
else
{
pOwner->SetItem(cell, NULL);
}
}
}m_pOwner = NULL;
m_wCell = 0;SetWindow(RESERVED_WINDOW);
#ifdef OFFLINE_SHOP
if(!GetRealID())
#endif
Save();
return (this);
}
}#ifdef __HIGHLIGHT_SYSTEM__
bool CItem::AddToCharacter(LPCHARACTER ch, TItemPos Cell, bool isHighLight)
#else
bool CItem::AddToCharacter(LPCHARACTER ch, TItemPos Cell)
#endif
{
assert(GetSectree() == NULL);
assert(m_pOwner == NULL);
WORD pos = Cell.cell;
BYTE window_type = Cell.window_type;if (INVENTORY == window_type)
{
if (m_wCell >= INVENTORY_MAX_NUM && BELT_INVENTORY_SLOT_START > m_wCell)
{
sys_err("CItem::AddToCharacter: cell overflow: %s to %s cell %d", m_pProto->szName, ch->GetName(), m_wCell);
return false;
}
}
else if (DRAGON_SOUL_INVENTORY == window_type)
{
if (m_wCell >= DRAGON_SOUL_INVENTORY_MAX_NUM)
{
sys_err("CItem::AddToCharacter: cell overflow: %s to %s cell %d", m_pProto->szName, ch->GetName(), m_wCell);
return false;
}
}if (ch->GetDesc())
m_dwLastOwnerPID = ch->GetPlayerID();event_cancel(&m_pkDestroyEvent);
#ifdef __HIGHLIGHT_SYSTEM__
ch->SetItem(TItemPos(window_type, pos), this, isHighLight);
#else
ch->SetItem(TItemPos(window_type, pos), this);
#endif
m_pOwner = ch;Save();
return true;
}LPITEM CItem::RemoveFromGround()
{
if (GetSectree())
{
SetOwnership(NULL);GetSectree()->RemoveEntity(this);
ViewCleanup();
Save();
}return (this);
}bool CItem::AddToGround(long lMapIndex, const PIXEL_POSITION & pos, bool skipOwnerCheck)
{
if (0 == lMapIndex)
{
sys_err("wrong map index argument: %d", lMapIndex);
return false;
}if (GetSectree())
{
sys_err("sectree already assigned");
return false;
}if (!skipOwnerCheck && m_pOwner)
{
sys_err("owner pointer not null");
return false;
}LPSECTREE tree = SECTREE_MANAGER::instance().Get(lMapIndex, pos.x, pos.y);
if (!tree)
{
sys_err("cannot find sectree by %dx%d", pos.x, pos.y);
return false;
}//tree->Touch();
SetWindow(GROUND);
SetXYZ(pos.x, pos.y, pos.z);
tree->InsertEntity(this);
UpdateSectree();
Save();
return true;
}bool CItem::DistanceValid(LPCHARACTER ch)
{
if (!GetSectree())
return false;int iDist = DISTANCE_APPROX(GetX() - ch->GetX(), GetY() - ch->GetY());
if (iDist > 300)
return false;return true;
}bool CItem::CanUsedBy(LPCHARACTER ch)
{
// Anti flag check
switch (ch->GetJob())
{
case JOB_WARRIOR:
if (GetAntiFlag() & ITEM_ANTIFLAG_WARRIOR)
return false;
break;case JOB_ASSASSIN:
if (GetAntiFlag() & ITEM_ANTIFLAG_ASSASSIN)
return false;
break;case JOB_SHAMAN:
if (GetAntiFlag() & ITEM_ANTIFLAG_SHAMAN)
return false;
break;case JOB_SURA:
if (GetAntiFlag() & ITEM_ANTIFLAG_SURA)
return false;
break;
#ifdef ENABLE_WOLFMAN_CHARACTER
case JOB_WOLFMAN:
if (GetAntiFlag() & ITEM_ANTIFLAG_WOLFMAN)
return false;
break;
#endif
}return true;
}
int CItem::FindEquipCell(LPCHARACTER ch, int iCandidateCell)
{
// 코스츔 아이템(ITEM_COSTUME)은 WearFlag 없어도 됨. (sub type으로 착용위치 구분. 귀찮게 또 wear flag 줄 필요가 있나..)
// 용혼석(ITEM_DS, ITEM_SPECIAL_DS)도 SUB_TYPE으로 구분. 신규 반지, 벨트는 ITEM_TYPE으로 구분
#ifdef SHININGSYSTEM
if ((0 == GetWearFlag() || ITEM_TOTEM == GetType()) && ITEM_COSTUME != GetType() && ITEM_DS != GetType() && ITEM_SPECIAL_DS != GetType() && ITEM_RING != GetType() && ITEM_BELT != GetType() && ITEM_SHINING != GetType())
return -1;
#else
if ((0 == GetWearFlag() || ITEM_TOTEM == GetType()) && ITEM_COSTUME != GetType() && ITEM_DS != GetType() && ITEM_SPECIAL_DS != GetType() && ITEM_RING != GetType() && ITEM_BELT != GetType())
return -1;
#endif
// 용혼석 슬롯을 WEAR로 처리할 수가 없어서(WEAR는 최대 32개까지 가능한데 용혼석을 추가하면 32가 넘는다.)
// 인벤토리의 특정 위치((INVENTORY_MAX_NUM + WEAR_MAX_NUM)부터 (INVENTORY_MAX_NUM + WEAR_MAX_NUM + DRAGON_SOUL_DECK_MAX_NUM * DS_SLOT_MAX - 1)까지)를
// 용혼석 슬롯으로 정함.
// return 할 때에, INVENTORY_MAX_NUM을 뺀 이유는,
// 본래 WearCell이 INVENTORY_MAX_NUM를 빼고 return 하기 때문.
if (GetType() == ITEM_DS || GetType() == ITEM_SPECIAL_DS)
{
if (iCandidateCell < 0)
{
return WEAR_MAX_NUM + GetSubType();
}
else
{
for (int i = 0; i < DRAGON_SOUL_DECK_MAX_NUM; i++)
{
if (WEAR_MAX_NUM + i * DS_SLOT_MAX + GetSubType() == iCandidateCell)
{
return iCandidateCell;
}
}
return -1;
}
}
else if (GetType() == ITEM_COSTUME)
{
if (GetSubType() == COSTUME_BODY)
return WEAR_COSTUME_BODY;
else if (GetSubType() == COSTUME_HAIR)
return WEAR_COSTUME_HAIR;
#ifdef ENABLE_MOUNT_COSTUME_SYSTEM
else if (GetSubType() == COSTUME_MOUNT)
return WEAR_COSTUME_MOUNT;
#endif
#ifdef __COSTUME_ACCE__
else if (GetSubType() == COSTUME_ACCE)
return WEAR_COSTUME_ACCE;
#endif
#ifdef ENABLE_WEAPON_COSTUME_SYSTEM
else if (GetSubType() == COSTUME_WEAPON)
return WEAR_COSTUME_WEAPON;
#endif
}
#if !defined(ENABLE_MOUNT_COSTUME_SYSTEM) && !defined(__COSTUME_ACCE__)
else if (GetType() == ITEM_RING)
{
if (ch->GetWear(WEAR_RING1))
return WEAR_RING2;
else
return WEAR_RING1;
}
#endif
else if (GetType() == ITEM_BELT)
return WEAR_BELT;
else if (GetWearFlag() & WEARABLE_BODY)
return WEAR_BODY;
else if (GetWearFlag() & WEARABLE_HEAD)
return WEAR_HEAD;
else if (GetWearFlag() & WEARABLE_FOOTS)
return WEAR_FOOTS;
else if (GetWearFlag() & WEARABLE_WRIST)
return WEAR_WRIST;
else if (GetWearFlag() & WEARABLE_WEAPON)
return WEAR_WEAPON;
else if (GetWearFlag() & WEARABLE_SHIELD)
return WEAR_SHIELD;
else if (GetWearFlag() & WEARABLE_NECK)
return WEAR_NECK;
else if (GetWearFlag() & WEARABLE_EAR)
return WEAR_EAR;
else if (GetWearFlag() & WEARABLE_ARROW)
return WEAR_ARROW;
else if (GetWearFlag() & WEARABLE_UNIQUE)
{
if (ch->GetWear(WEAR_UNIQUE1))
return WEAR_UNIQUE2;
else
return WEAR_UNIQUE1;
}
#ifdef SHININGSYSTEM
else if (GetType() == ITEM_SHINING)
{
if (GetSubType() == SHINING_WEAPON) {
for (int i = WEAR_SHINING_WEAPON_1; i <= WEAR_SHINING_WEAPON_3; i++)
{
if (!ch->GetWear(i))
return i;
}
return WEAR_SHINING_WEAPON_1;
}
else if (GetSubType() == SHINING_ARMOR) {
if (ch->GetWear(WEAR_SHINING_ARMOR_1))
return WEAR_SHINING_ARMOR_2;
else
return WEAR_SHINING_ARMOR_1;
}
else if (GetSubType() == SHINING_SPECIAL) {
return WEAR_SHINING_SPECIAL;
}
}
#endif
// 수집 퀘스트를 위한 아이템이 박히는곳으로 한번 박히면 절대 E수 없다.
else if (GetWearFlag() & WEARABLE_ABILITY)
{
if (!ch->GetWear(WEAR_ABILITY1))
{
return WEAR_ABILITY1;
}
else if (!ch->GetWear(WEAR_ABILITY2))
{
return WEAR_ABILITY2;
}
else if (!ch->GetWear(WEAR_ABILITY3))
{
return WEAR_ABILITY3;
}
else if (!ch->GetWear(WEAR_ABILITY4))
{
return WEAR_ABILITY4;
}
else if (!ch->GetWear(WEAR_ABILITY5))
{
return WEAR_ABILITY5;
}
else if (!ch->GetWear(WEAR_ABILITY6))
{
return WEAR_ABILITY6;
}
else if (!ch->GetWear(WEAR_ABILITY7))
{
return WEAR_ABILITY7;
}
else if (!ch->GetWear(WEAR_ABILITY8))
{
return WEAR_ABILITY8;
}
else
{
return -1;
}
}
return -1;
}void CItem::ModifyPoints(bool bAdd)
{
int accessoryGrade;// 무기와 갑옷만 소켓을 적용시킨다.
if (false == IsAccessoryForSocket())
{
if (m_pProto->bType == ITEM_WEAPON || m_pProto->bType == ITEM_ARMOR)
{
// 소켓이 속성강화에 사용되는 경우 적용하지 않는다 (ARMOR_WRIST ARMOR_NECK ARMOR_EAR)
for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
{
DWORD dwVnum;if ((dwVnum = GetSocket(i)) <= 2)
continue;TItemTable * p = ITEM_MANAGER::instance().GetTable(dwVnum);
if (!p)
{
sys_err("cannot find table by vnum %u", dwVnum);
continue;
}if (ITEM_METIN == p->bType)
{
//m_pOwner->ApplyPoint(p->alValues[0], bAdd ? p->alValues[1] : -p->alValues[1]);
for (int i = 0; i < ITEM_APPLY_MAX_NUM; ++i)
{
if (p->aApplies.bType == APPLY_NONE)
continue;if (p->aApplies.bType == APPLY_SKILL)
m_pOwner->ApplyPoint(p->aApplies.bType, bAdd ? p->aApplies.lValue : p->aApplies.lValue ^ 0x00800000);
else
m_pOwner->ApplyPoint(p->aApplies.bType, bAdd ? p->aApplies.lValue : -p->aApplies.lValue);
}
}
}
}accessoryGrade = 0;
}
else
{
accessoryGrade = MIN(GetAccessorySocketGrade(), ITEM_ACCESSORY_SOCKET_MAX_NUM);
}for (int i = 0; i < ITEM_APPLY_MAX_NUM; ++i)
{
if (m_pProto->aApplies.bType == APPLY_NONE)
continue;long value = m_pProto->aApplies.lValue;
if (m_pProto->aApplies.bType == APPLY_SKILL)
{
m_pOwner->ApplyPoint(m_pProto->aApplies.bType, bAdd ? value : value ^ 0x00800000);
}
else
{
if (0 != accessoryGrade)
value += MAX(accessoryGrade, value * aiAccessorySocketEffectivePct[accessoryGrade] / 100);m_pOwner->ApplyPoint(m_pProto->aApplies.bType, bAdd ? value : -value);
}
}
// 초승달의 반지, 할로윈 사탕, 행복의 반지, 영원한 사랑의 펜던트의 경우
// 기존의 하드 코딩으로 강제로 속성을 부여했지만,
// 그 부분을 제거하고 special item group 테이블에서 속성을 부여하도록 변경하였다.
// 하지만 하드 코딩되어있을 때 생성된 아이템이 남아있을 수도 있어서 특수처리 해놓는다.
// 이 아이템들의 경우, 밑에 ITEM_UNIQUE일 때의 처리로 속성이 부여되기 때문에,
// 아이템에 박혀있는 attribute는 적용하지 않고 넘어간다.
#ifdef __COSTUME_ACCE__
if (ITEM_COSTUME == GetType() && COSTUME_ACCE == GetSubType())
{
TItemTable * p = ITEM_MANAGER::instance().GetTable(GetSocket(1));if (p) {
for (int i = 0; i < ITEM_APPLY_MAX_NUM; ++i)
{
if (p->aApplies.bType == APPLY_NONE)
continue;int value = p->aApplies.lValue;
if (value < 0)
value = 1;
else
value = int(float(value) / 100.0f * float(GetSocket(0))) <= 0 ? 1 : int(float(value) / 100.0f * float(GetSocket(0)));if (p->aApplies.bType == APPLY_SKILL)
{
m_pOwner->ApplyPoint(p->aApplies.bType, bAdd ? value : value ^ 0x00800000);
}
else
{
m_pOwner->ApplyPoint(p->aApplies.bType, bAdd ? value : -value);
}
}
}
}
#endif
if (true == CItemVnumHelper::IsRamadanMoonRing(GetVnum()) || true == CItemVnumHelper::IsHalloweenCandy(GetVnum())
|| true == CItemVnumHelper::IsHappinessRing(GetVnum()) || true == CItemVnumHelper::IsLovePendant(GetVnum()))
{
// Do not anything.
}
else
{
for (int i = 0; i < ITEM_ATTRIBUTE_MAX_NUM; ++i)
{
if (GetAttributeType(i))
{
const TPlayerItemAttribute& ia = GetAttribute(i);
short attrVal = ia.sValue;
#ifdef __COSTUME_ACCE__
if (ITEM_COSTUME == GetType() && COSTUME_ACCE == GetSubType())
{
if (attrVal < 0)
attrVal = 1;
else
attrVal = int(float(attrVal) / 100.0f * float(GetSocket(0)));// <= 0 ? 1 : int(float(attrVal) / 100.0f * float(GetSocket(0)));
}
#endif
if (ia.bType == APPLY_SKILL)
m_pOwner->ApplyPoint(ia.bType, bAdd ? ia.sValue : ia.sValue ^ 0x00800000);
else
m_pOwner->ApplyPoint(ia.bType, bAdd ? ia.sValue : -ia.sValue);
}
}
}switch (m_pProto->bType)
{
case ITEM_PICK:
case ITEM_ROD:
{
if (bAdd)
{
if (m_wCell == INVENTORY_MAX_NUM + WEAR_WEAPON)
m_pOwner->SetPart(PART_WEAPON, GetVnum());
}
else
{
if (m_wCell == INVENTORY_MAX_NUM + WEAR_WEAPON)
m_pOwner->SetPart(PART_WEAPON, 0);
}
}
break;case ITEM_WEAPON:
{
#ifdef ENABLE_WEAPON_COSTUME_SYSTEM
if (0 != m_pOwner->GetWear(WEAR_COSTUME_WEAPON))
break;
#endifif (bAdd)
{
#ifdef __CHANGE_LOOK_SYSTEM__
if (m_wCell == INVENTORY_MAX_NUM + WEAR_WEAPON)
m_pOwner->SetPart(PART_WEAPON, GetItemLook() > 0 ? GetItemLook() : GetVnum());
#else
if (m_wCell == INVENTORY_MAX_NUM + WEAR_WEAPON)
m_pOwner->SetPart(PART_WEAPON, GetVnum());
#endif
}
else
{
if (m_wCell == INVENTORY_MAX_NUM + WEAR_WEAPON)
m_pOwner->SetPart(PART_WEAPON, 0);
}
}
break;case ITEM_ARMOR:
{
// 코스츔 body를 입고있다면 armor는 벗던 입던 상관 없이 비주얼에 영향을 주면 안 됨.
if (0 != m_pOwner->GetWear(WEAR_COSTUME_BODY))
break;if (GetSubType() == ARMOR_BODY || GetSubType() == ARMOR_HEAD || GetSubType() == ARMOR_FOOTS || GetSubType() == ARMOR_SHIELD)
{
if (bAdd)
{
#ifdef __CHANGE_LOOK_SYSTEM__
if (GetProto()->bSubType == ARMOR_BODY)
m_pOwner->SetPart(PART_MAIN, GetItemLook() > 0 ? GetItemLook() : GetVnum());
#else
if (GetProto()->bSubType == ARMOR_BODY)
m_pOwner->SetPart(PART_MAIN, GetVnum());
#endif
}
else
{
if (GetProto()->bSubType == ARMOR_BODY)
m_pOwner->SetPart(PART_MAIN, m_pOwner->GetOriginalPart(PART_MAIN));
}
}
}
break;// 코스츔 아이템 입었을 때 캐릭터 parts 정보 세팅. 기존 스타일대로 추가함..
case ITEM_COSTUME:
{
DWORD toSetValue = this->GetVnum();
EParts toSetPart = PART_MAX_NUM;// 갑옷 코스츔
if (GetSubType() == COSTUME_BODY)
{
toSetPart = PART_MAIN;if (false == bAdd)
{
// 코스츔 갑옷을 벗었을 때 원래 갑옷을 입고 있었다면 그 갑옷으로 look 세팅, 입지 않았다면 default look
#ifdef __CHANGE_LOOK_SYSTEM__
CItem* pArmor = m_pOwner->GetWear(WEAR_BODY);
#else
const CItem* pArmor = m_pOwner->GetWear(WEAR_BODY);
#endif
#ifdef __CHANGE_LOOK_SYSTEM__
toSetValue = (NULL != pArmor) ? pArmor->GetItemLook() > 0 ? pArmor->GetItemLook() : pArmor->GetVnum() : m_pOwner->GetOriginalPart(PART_MAIN);
#else
toSetValue = (NULL != pArmor) ? pArmor->GetVnum() : m_pOwner->GetOriginalPart(PART_MAIN);
#endif
}}
// 헤어 코스츔
else if (GetSubType() == COSTUME_HAIR)
{
toSetPart = PART_HAIR;// 코스츔 헤어는 shape값을 item proto의 value3에 세팅하도록 함. 특별한 이유는 없고 기존 갑옷(ARMOR_BODY)의 shape값이 프로토의 value3에 있어서 헤어도 같이 value3으로 함.
// [NOTE] 갑옷은 아이템 vnum을 보내고 헤어는 shape(value3)값을 보내는 이유는.. 기존 시스템이 그렇게 되어있음...
toSetValue = (true == bAdd) ? this->GetValue(3) : 0;
}#ifdef ENABLE_MOUNT_COSTUME_SYSTEM
else if (GetSubType() == COSTUME_MOUNT)
{
// not need to do a thing in here
}
#endif#ifdef ENABLE_WEAPON_COSTUME_SYSTEM
else if (GetSubType() == COSTUME_WEAPON)
{
toSetPart = PART_WEAPON;
if (false == bAdd)
{
#ifdef __CHANGE_LOOK_SYSTEM__
CItem* pWeapon = m_pOwner->GetWear(WEAR_WEAPON);
#else
const CItem* pWeapon = m_pOwner->GetWear(WEAR_WEAPON);
#endif
#ifdef __CHANGE_LOOK_SYSTEM__
toSetValue = (NULL != pWeapon) ? pWeapon->GetItemLook() > 0 ? pWeapon->GetItemLook() : pWeapon->GetVnum() : m_pOwner->GetOriginalPart(PART_WEAPON);
#else
toSetValue = (NULL != pWeapon) ? pWeapon->GetVnum() : m_pOwner->GetOriginalPart(PART_WEAPON);
#endif
}
}
#endif
#ifdef __COSTUME_ACCE__
else if (GetSubType() == COSTUME_ACCE) {
toSetPart = PART_ACCE;
toSetValue = (true == bAdd) ? this->GetVnum() : 0;
}
#endifif (PART_MAX_NUM != toSetPart)
{
m_pOwner->SetPart((BYTE)toSetPart, toSetValue);
m_pOwner->UpdatePacket();
}
}
break;
case ITEM_UNIQUE:
{
if (0 != GetSIGVnum())
{
const CSpecialItemGroup* pItemGroup = ITEM_MANAGER::instance().GetSpecialItemGroup(GetSIGVnum());
if (NULL == pItemGroup)
break;
DWORD dwAttrVnum = pItemGroup->GetAttrVnum(GetVnum());
const CSpecialAttrGroup* pAttrGroup = ITEM_MANAGER::instance().GetSpecialAttrGroup(dwAttrVnum);
if (NULL == pAttrGroup)
break;
for (itertype (pAttrGroup->m_vecAttrs) it = pAttrGroup->m_vecAttrs.begin(); it != pAttrGroup->m_vecAttrs.end(); it++)
{
m_pOwner->ApplyPoint(it->apply_type, bAdd ? it->apply_value : -it->apply_value);
}
}
}
break;
}
}bool CItem::IsEquipable() const
{
switch (this->GetType())
{
case ITEM_COSTUME:
case ITEM_ARMOR:
case ITEM_WEAPON:
case ITEM_ROD:
case ITEM_PICK:
case ITEM_UNIQUE:
case ITEM_DS:
case ITEM_SPECIAL_DS:
case ITEM_RING:
case ITEM_BELT:
#ifdef SHININGSYSTEM
case ITEM_SHINING:
#endif
return true;
}return false;
}#define ENABLE_IMMUNE_FIX
// return false on error state
#ifdef ENABLE_5_INVENTORY
bool CItem::EquipTo(LPCHARACTER ch, WORD bWearCell)
#else
bool CItem::EquipTo(LPCHARACTER ch, BYTE bWearCell)
#endif
{
if (!ch)
{
sys_err("EquipTo: nil character");
return false;
}// 용혼석 슬롯 index는 WEAR_MAX_NUM 보다 큼.
if (IsDragonSoul())
{
if (bWearCell < WEAR_MAX_NUM || bWearCell >= WEAR_MAX_NUM + DRAGON_SOUL_DECK_MAX_NUM * DS_SLOT_MAX)
{
sys_err("EquipTo: invalid dragon soul cell (this: #%d %s wearflag: %d cell: %d)", GetOriginalVnum(), GetName(), GetSubType(), bWearCell - WEAR_MAX_NUM);
return false;
}
}
else
{
if (bWearCell >= WEAR_MAX_NUM)
{
sys_err("EquipTo: invalid wear cell (this: #%d %s wearflag: %d cell: %d)", GetOriginalVnum(), GetName(), GetWearFlag(), bWearCell);
return false;
}
}if (ch->GetWear(bWearCell))
{
sys_err("EquipTo: item already exist (this: #%d %s cell: %d %s)", GetOriginalVnum(), GetName(), bWearCell, ch->GetWear(bWearCell)->GetName());
return false;
}if (GetOwner())
RemoveFromCharacter();ch->SetWear(bWearCell, this); // 여기서 패킷 나감
m_pOwner = ch;
m_bEquipped = true;
m_wCell = INVENTORY_MAX_NUM + bWearCell;#ifndef ENABLE_IMMUNE_FIX
DWORD dwImmuneFlag = 0;for (int i = 0; i < WEAR_MAX_NUM; ++i)
{
if (m_pOwner->GetWear(i))
{
// m_pOwner->ChatPacket(CHAT_TYPE_INFO, "unequip immuneflag(%u)", m_pOwner->GetWear(i)->m_pProto->dwImmuneFlag); // always 0
SET_BIT(dwImmuneFlag, m_pOwner->GetWear(i)->m_pProto->dwImmuneFlag);
}
}m_pOwner->SetImmuneFlag(dwImmuneFlag);
#endifif (IsDragonSoul())
{
DSManager::instance().ActivateDragonSoul(this);
}
else
{
ModifyPoints(true);
StartUniqueExpireEvent();
if (-1 != GetProto()->cLimitTimerBasedOnWearIndex)
StartTimerBasedOnWearExpireEvent();// ACCESSORY_REFINE
StartAccessorySocketExpireEvent();
// END_OF_ACCESSORY_REFINE
}ch->BuffOnAttr_AddBuffsFromItem(this);
m_pOwner->ComputeBattlePoints();
m_pOwner->UpdatePacket();
Save();
return (true);
}bool CItem::Unequip()
{
if (!m_pOwner || GetCell() < INVENTORY_MAX_NUM)
{
// ITEM_OWNER_INVALID_PTR_BUG
sys_err("%s %u m_pOwner %p, GetCell %d",
GetName(), GetID(), get_pointer(m_pOwner), GetCell());
// END_OF_ITEM_OWNER_INVALID_PTR_BUG
return false;
}if (this != m_pOwner->GetWear(GetCell() - INVENTORY_MAX_NUM))
{
sys_err("m_pOwner->GetWear() != this");
return false;
}//신규 말 아이템 제거시 처리
if (IsRideItem())
ClearMountAttributeAndAffect();if (IsDragonSoul())
{
DSManager::instance().DeactivateDragonSoul(this);
}
else
{
ModifyPoints(false);
}StopUniqueExpireEvent();
if (-1 != GetProto()->cLimitTimerBasedOnWearIndex)
StopTimerBasedOnWearExpireEvent();// ACCESSORY_REFINE
StopAccessorySocketExpireEvent();
// END_OF_ACCESSORY_REFINE
m_pOwner->BuffOnAttr_RemoveBuffsFromItem(this);m_pOwner->SetWear(GetCell() - INVENTORY_MAX_NUM, NULL);
#ifndef ENABLE_IMMUNE_FIX
DWORD dwImmuneFlag = 0;for (int i = 0; i < WEAR_MAX_NUM; ++i)
{
if (m_pOwner->GetWear(i))
{
// m_pOwner->ChatPacket(CHAT_TYPE_INFO, "unequip immuneflag(%u)", m_pOwner->GetWear(i)->m_pProto->dwImmuneFlag); // always 0
SET_BIT(dwImmuneFlag, m_pOwner->GetWear(i)->m_pProto->dwImmuneFlag);
}
}m_pOwner->SetImmuneFlag(dwImmuneFlag);
#endifm_pOwner->ComputeBattlePoints();
m_pOwner->UpdatePacket();
m_pOwner = NULL;
m_wCell = 0;
m_bEquipped = false;return true;
}long CItem::GetValue(DWORD idx)
{
assert(idx < ITEM_VALUES_MAX_NUM);
return GetProto()->alValues[idx];
}void CItem::SetExchanging(bool bOn)
{
m_bExchanging = bOn;
}void CItem::Save()
{
if (m_bSkipSave)
return;ITEM_MANAGER::instance().DelayedSave(this);
}bool CItem::CreateSocket(BYTE bSlot, BYTE bGold)
{
assert(bSlot < ITEM_SOCKET_MAX_NUM);if (m_alSockets[bSlot] != 0)
{
sys_err("Item::CreateSocket : socket already exist %s %d", GetName(), bSlot);
return false;
}if (bGold)
m_alSockets[bSlot] = 2;
else
m_alSockets[bSlot] = 1;UpdatePacket();
Save();
return true;
}void CItem::SetSockets(const long * c_al)
{
thecore_memcpy(m_alSockets, c_al, sizeof(m_alSockets));
Save();
}void CItem::SetSocket(int i, long v, bool bLog)
{
assert(i < ITEM_SOCKET_MAX_NUM);
m_alSockets = v;
UpdatePacket();
Save();
if (bLog)
{
#ifdef ENABLE_NEWSTUFF
if (g_iDbLogLevel>=LOG_LEVEL_MAX)
#endif
LogManager::instance().ItemLog(i, v, 0, GetID(), "SET_SOCKET", "", "", GetOriginalVnum());
}
}#ifdef ENABLE_YANG_LIMIT
long long CItem::GetGold()
#else
int CItem::GetGold()
#endif
{
if (IS_SET(GetFlag(), ITEM_FLAG_COUNT_PER_1GOLD))
{
if (GetProto()->dwGold == 0)
return GetCount();
else
return GetCount() / GetProto()->dwGold;
}
else
return GetProto()->dwGold;
}#ifdef ENABLE_YANG_LIMIT
long long CItem::GetShopBuyPrice()
#else
int CItem::GetShopBuyPrice()
#endif
{
return GetProto()->dwShopBuyPrice;
}bool CItem::IsOwnership(LPCHARACTER ch)
{
if (!m_pkOwnershipEvent)
return true;return m_dwOwnershipPID == ch->GetPlayerID() ? true : false;
}EVENTFUNC(ownership_event)
{
item_event_info* info = dynamic_cast<item_event_info*>( event->info );if ( info == NULL )
{
sys_err( "ownership_event> <Factor> Null pointer" );
return 0;
}LPITEM pkItem = info->item;
pkItem->SetOwnershipEvent(NULL);
TPacketGCItemOwnership p;
p.bHeader = HEADER_GC_ITEM_OWNERSHIP;
p.dwVID = pkItem->GetVID();
p.szName[0] = '\0';pkItem->PacketAround(&p, sizeof(p));
return 0;
}void CItem::SetOwnershipEvent(LPEVENT pkEvent)
{
m_pkOwnershipEvent = pkEvent;
}void CItem::SetOwnership(LPCHARACTER ch, int iSec)
{
if (!ch)
{
if (m_pkOwnershipEvent)
{
event_cancel(&m_pkOwnershipEvent);
m_dwOwnershipPID = 0;TPacketGCItemOwnership p;
p.bHeader = HEADER_GC_ITEM_OWNERSHIP;
p.dwVID = m_dwVID;
p.szName[0] = '\0';PacketAround(&p, sizeof(p));
}
return;
}if (m_pkOwnershipEvent)
return;if (iSec <= 10)
iSec = 30;m_dwOwnershipPID = ch->GetPlayerID();
item_event_info* info = AllocEventInfo<item_event_info>();
strlcpy(info->szOwnerName, ch->GetName(), sizeof(info->szOwnerName));
info->item = this;SetOwnershipEvent(event_create(ownership_event, info, PASSES_PER_SEC(iSec)));
TPacketGCItemOwnership p;
p.bHeader = HEADER_GC_ITEM_OWNERSHIP;
p.dwVID = m_dwVID;
strlcpy(p.szName, ch->GetName(), sizeof(p.szName));PacketAround(&p, sizeof(p));
}int CItem::GetSocketCount()
{
for (int i = 0; i < ITEM_SOCKET_MAX_NUM; i++)
{
if (GetSocket(i) == 0)
return i;
}
return ITEM_SOCKET_MAX_NUM;
}bool CItem::AddSocket()
{
int count = GetSocketCount();
if (count == ITEM_SOCKET_MAX_NUM)
return false;
m_alSockets[count] = 1;
return true;
}void CItem::AlterToSocketItem(int iSocketCount)
{
if (iSocketCount >= ITEM_SOCKET_MAX_NUM)
{
sys_log(0, "Invalid Socket Count %d, set to maximum", ITEM_SOCKET_MAX_NUM);
iSocketCount = ITEM_SOCKET_MAX_NUM;
}for (int i = 0; i < iSocketCount; ++i)
SetSocket(i, 1);
}void CItem::AlterToMagicItem()
{
int idx = GetAttributeSetIndex();if (idx < 0)
return;// Appeariance Second Third
// Weapon 50 20 5
// Armor 30 10 2
// Acc 20 10 1int iSecondPct;
int iThirdPct;switch (GetType())
{
case ITEM_WEAPON:
iSecondPct = 20;
iThirdPct = 5;
break;case ITEM_ARMOR:
case ITEM_COSTUME:
if (GetSubType() == ARMOR_BODY)
{
iSecondPct = 10;
iThirdPct = 2;
}
else
{
iSecondPct = 10;
iThirdPct = 1;
}
break;default:
return;
}// 100% 확률로 좋은 속성 하나
PutAttribute(aiItemMagicAttributePercentHigh);if (number(1, 100) <= iSecondPct)
PutAttribute(aiItemMagicAttributePercentLow);if (number(1, 100) <= iThirdPct)
PutAttribute(aiItemMagicAttributePercentLow);
}DWORD CItem::GetRefineFromVnum()
{
return ITEM_MANAGER::instance().GetRefineFromVnum(GetVnum());
}int CItem::GetRefineLevel()
{
const char* name = GetBaseName();
char* p = const_cast<char*>(strrchr(name, '+'));if (!p)
return 0;int rtn = 0;
str_to_number(rtn, p+1);const char* locale_name = GetName();
p = const_cast<char*>(strrchr(locale_name, '+'));if (p)
{
int locale_rtn = 0;
str_to_number(locale_rtn, p+1);
if (locale_rtn != rtn)
{
sys_err("refine_level_based_on_NAME(%d) is not equal to refine_level_based_on_LOCALE_NAME(%d).", rtn, locale_rtn);
}
}return rtn;
}bool CItem::IsPolymorphItem()
{
return GetType() == ITEM_POLYMORPH;
}EVENTFUNC(unique_expire_event)
{
item_event_info* info = dynamic_cast<item_event_info*>( event->info );if ( info == NULL )
{
sys_err( "unique_expire_event> <Factor> Null pointer" );
return 0;
}LPITEM pkItem = info->item;
if (pkItem->GetValue(2) == 0)
{
if (pkItem->GetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME) <= 1)
{
sys_log(0, "UNIQUE_ITEM: expire %s %u", pkItem->GetName(), pkItem->GetID());
pkItem->SetUniqueExpireEvent(NULL);
ITEM_MANAGER::instance().RemoveItem(pkItem, "UNIQUE_EXPIRE");
return 0;
}
else
{
pkItem->SetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME, pkItem->GetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME) - 1);
return PASSES_PER_SEC(60);
}
}
else
{
time_t cur = get_global_time();if (pkItem->GetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME) <= cur)
{
pkItem->SetUniqueExpireEvent(NULL);
ITEM_MANAGER::instance().RemoveItem(pkItem, "UNIQUE_EXPIRE");
return 0;
}
else
{
// 게임 내에 시간제 아이템들이 빠릿빠릿하게 사라지지 않는 버그가 있어
// 수정
// by rtsummit
if (pkItem->GetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME) - cur < 600)
return PASSES_PER_SEC(pkItem->GetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME) - cur);
else
return PASSES_PER_SEC(600);
}
}
}// 시간 후불제
// timer를 시작할 때에 시간 차감하는 것이 아니라,
// timer가 발화할 때에 timer가 동작한 시간 만큼 시간 차감을 한다.
EVENTFUNC(timer_based_on_wear_expire_event)
{
item_event_info* info = dynamic_cast<item_event_info*>( event->info );if ( info == NULL )
{
sys_err( "expire_event <Factor> Null pointer" );
return 0;
}LPITEM pkItem = info->item;
int remain_time = pkItem->GetSocket(ITEM_SOCKET_REMAIN_SEC) - processing_time/passes_per_sec;
if (remain_time <= 0)
{
sys_log(0, "ITEM EXPIRED : expired %s %u", pkItem->GetName(), pkItem->GetID());
pkItem->SetTimerBasedOnWearExpireEvent(NULL);
pkItem->SetSocket(ITEM_SOCKET_REMAIN_SEC, 0);// 일단 timer based on wear 용혼석은 시간 다 되었다고 없애지 않는다.
if (pkItem->IsDragonSoul())
{
DSManager::instance().DeactivateDragonSoul(pkItem);
}
else
{
ITEM_MANAGER::instance().RemoveItem(pkItem, "TIMER_BASED_ON_WEAR_EXPIRE");
}
return 0;
}
pkItem->SetSocket(ITEM_SOCKET_REMAIN_SEC, remain_time);
return PASSES_PER_SEC (MIN (60, remain_time));
}void CItem::SetUniqueExpireEvent(LPEVENT pkEvent)
{
m_pkUniqueExpireEvent = pkEvent;
}void CItem::SetTimerBasedOnWearExpireEvent(LPEVENT pkEvent)
{
m_pkTimerBasedOnWearExpireEvent = pkEvent;
}EVENTFUNC(real_time_expire_event)
{
const item_vid_event_info* info = reinterpret_cast<const item_vid_event_info*>(event->info);if (NULL == info)
return 0;const LPITEM item = ITEM_MANAGER::instance().FindByVID( info->item_vid );
if (NULL == item)
return 0;const time_t current = get_global_time();
if (current > item->GetSocket(0))
{
switch (item->GetVnum())
{
if(item->IsNewMountItem())
{
if (item->GetSocket(2) != 0)
item->ClearMountAttributeAndAffect();
}
break;
}
#ifdef SHOP_SEARCH
if (item->GetOwner() && CShopSearchHelper::IsGlass(item->GetVnum()))
CShopSearchHelper::Close(item->GetVnum(), item->GetOwner());
#endif
ITEM_MANAGER::instance().RemoveItem(item, "REAL_TIME_EXPIRE");return 0;
}return PASSES_PER_SEC(1);
}void CItem::StartRealTimeExpireEvent()
{
if (m_pkRealTimeExpireEvent)
return;
for (int i=0 ; i < ITEM_LIMIT_MAX_NUM ; i++)
{
if (LIMIT_REAL_TIME == GetProto()->aLimits.bType || LIMIT_REAL_TIME_START_FIRST_USE == GetProto()->aLimits.bType)
{
item_vid_event_info* info = AllocEventInfo<item_vid_event_info>();
info->item_vid = GetVID();m_pkRealTimeExpireEvent = event_create( real_time_expire_event, info, PASSES_PER_SEC(1));
sys_log(0, "REAL_TIME_EXPIRE: StartRealTimeExpireEvent");
return;
}
}
}bool CItem::IsRealTimeItem()
{
if(!GetProto())
return false;
for (int i=0 ; i < ITEM_LIMIT_MAX_NUM ; i++)
{
if (LIMIT_REAL_TIME == GetProto()->aLimits.bType)
return true;
}
return false;
}void CItem::StartUniqueExpireEvent()
{
if (GetType() != ITEM_UNIQUE)
return;if (m_pkUniqueExpireEvent)
return;//기간제 아이템일 경우 시간제 아이템은 동작하지 않는다
if (IsRealTimeItem())
return;// HARD CODING
if (GetVnum() == UNIQUE_ITEM_HIDE_ALIGNMENT_TITLE)
m_pOwner->ShowAlignment(false);int iSec = GetSocket(ITEM_SOCKET_UNIQUE_SAVE_TIME);
if (iSec == 0)
iSec = 60;
else
iSec = MIN(iSec, 60);SetSocket(ITEM_SOCKET_UNIQUE_SAVE_TIME, 0);
item_event_info* info = AllocEventInfo<item_event_info>();
info->item = this;SetUniqueExpireEvent(event_create(unique_expire_event, info, PASSES_PER_SEC(iSec)));
}// 시간 후불제
// timer_based_on_wear_expire_event 설명 참조
void CItem::StartTimerBasedOnWearExpireEvent()
{
if (m_pkTimerBasedOnWearExpireEvent)
return;//기간제 아이템일 경우 시간제 아이템은 동작하지 않는다
if (IsRealTimeItem())
return;if (-1 == GetProto()->cLimitTimerBasedOnWearIndex)
return;int iSec = GetSocket(0);
// 남은 시간을 분단위로 끊기 위해...
if (0 != iSec)
{
iSec %= 60;
if (0 == iSec)
iSec = 60;
}item_event_info* info = AllocEventInfo<item_event_info>();
info->item = this;SetTimerBasedOnWearExpireEvent(event_create(timer_based_on_wear_expire_event, info, PASSES_PER_SEC(iSec)));
}void CItem::StopUniqueExpireEvent()
{
if (!m_pkUniqueExpireEvent)
return;if (GetValue(2) != 0) // 게임시간제 이외의 아이템은 UniqueExpireEvent를 중단할 수 없다.
return;// HARD CODING
if (GetVnum() == UNIQUE_ITEM_HIDE_ALIGNMENT_TITLE)
m_pOwner->ShowAlignment(true);SetSocket(ITEM_SOCKET_UNIQUE_SAVE_TIME, event_time(m_pkUniqueExpireEvent) / passes_per_sec);
event_cancel(&m_pkUniqueExpireEvent);ITEM_MANAGER::instance().SaveSingleItem(this);
}void CItem::StopTimerBasedOnWearExpireEvent()
{
if (!m_pkTimerBasedOnWearExpireEvent)
return;int remain_time = GetSocket(ITEM_SOCKET_REMAIN_SEC) - event_processing_time(m_pkTimerBasedOnWearExpireEvent) / passes_per_sec;
SetSocket(ITEM_SOCKET_REMAIN_SEC, remain_time);
event_cancel(&m_pkTimerBasedOnWearExpireEvent);ITEM_MANAGER::instance().SaveSingleItem(this);
}void CItem::ApplyAddon(int iAddonType)
{
CItemAddonManager::instance().ApplyAddonTo(iAddonType, this);
}int CItem::GetSpecialGroup() const
{
return ITEM_MANAGER::instance().GetSpecialGroupFromItem(GetVnum());
}//
// 악세서리 소켓 처리.
//
bool CItem::IsAccessoryForSocket()
{
return (m_pProto->bType == ITEM_ARMOR && (m_pProto->bSubType == ARMOR_WRIST || m_pProto->bSubType == ARMOR_NECK || m_pProto->bSubType == ARMOR_EAR)) ||
(m_pProto->bType == ITEM_BELT); // 2013년 2월 새로 추가된 '벨트' 아이템의 경우 기획팀에서 악세서리 소켓 시스템을 그대로 이용하자고 함.
}void CItem::SetAccessorySocketGrade(int iGrade)
{
SetSocket(0, MINMAX(0, iGrade, GetAccessorySocketMaxGrade()));int iDownTime = aiAccessorySocketDegradeTime[GetAccessorySocketGrade()];
//if (test_server)
// iDownTime /= 60;SetAccessorySocketDownGradeTime(iDownTime);
}void CItem::SetAccessorySocketMaxGrade(int iMaxGrade)
{
SetSocket(1, MINMAX(0, iMaxGrade, ITEM_ACCESSORY_SOCKET_MAX_NUM));
}void CItem::SetAccessorySocketDownGradeTime(DWORD time)
{
SetSocket(2, time);if (test_server && GetOwner())
GetOwner()->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s에서 소켓 빠질때까지 남은 시간 %d"), GetName(), time);
}EVENTFUNC(accessory_socket_expire_event)
{
item_vid_event_info* info = dynamic_cast<item_vid_event_info*>( event->info );if ( info == NULL )
{
sys_err( "accessory_socket_expire_event> <Factor> Null pointer" );
return 0;
}LPITEM item = ITEM_MANAGER::instance().FindByVID(info->item_vid);
if (item->GetAccessorySocketDownGradeTime() <= 1)
{
degrade:
item->SetAccessorySocketExpireEvent(NULL);
item->AccessorySocketDegrade();
return 0;
}
else
{
int iTime = item->GetAccessorySocketDownGradeTime() - 60;if (iTime <= 1)
goto degrade;item->SetAccessorySocketDownGradeTime(iTime);
if (iTime > 60)
return PASSES_PER_SEC(60);
else
return PASSES_PER_SEC(iTime);
}
}void CItem::StartAccessorySocketExpireEvent()
{
if (!IsAccessoryForSocket())
return;if (m_pkAccessorySocketExpireEvent)
return;if (GetAccessorySocketMaxGrade() == 0)
return;if (GetAccessorySocketGrade() == 0)
return;int iSec = GetAccessorySocketDownGradeTime();
SetAccessorySocketExpireEvent(NULL);if (iSec <= 1)
iSec = 5;
else
iSec = MIN(iSec, 60);item_vid_event_info* info = AllocEventInfo<item_vid_event_info>();
info->item_vid = GetVID();SetAccessorySocketExpireEvent(event_create(accessory_socket_expire_event, info, PASSES_PER_SEC(iSec)));
}void CItem::StopAccessorySocketExpireEvent()
{
if (!m_pkAccessorySocketExpireEvent)
return;if (!IsAccessoryForSocket())
return;int new_time = GetAccessorySocketDownGradeTime() - (60 - event_time(m_pkAccessorySocketExpireEvent) / passes_per_sec);
event_cancel(&m_pkAccessorySocketExpireEvent);
if (new_time <= 1)
{
AccessorySocketDegrade();
}
else
{
SetAccessorySocketDownGradeTime(new_time);
}
}bool CItem::IsRideItem()
{
if (ITEM_UNIQUE == GetType() && UNIQUE_SPECIAL_RIDE == GetSubType())
return true;
if (ITEM_UNIQUE == GetType() && UNIQUE_SPECIAL_MOUNT_RIDE == GetSubType())
return true;
#ifdef ENABLE_MOUNT_COSTUME_SYSTEM
if (ITEM_COSTUME == GetType() && COSTUME_MOUNT == GetSubType())
return true;
#endif
return false;
}bool CItem::IsRamadanRing()
{
if (GetVnum() == UNIQUE_ITEM_RAMADAN_RING)
return true;
return false;
}void CItem::ClearMountAttributeAndAffect()
{
LPCHARACTER ch = GetOwner();ch->RemoveAffect(AFFECT_MOUNT);
ch->RemoveAffect(AFFECT_MOUNT_BONUS);ch->MountVnum(0);
ch->PointChange(POINT_ST, 0);
ch->PointChange(POINT_DX, 0);
ch->PointChange(POINT_HT, 0);
ch->PointChange(POINT_IQ, 0);
}// fixme
// 이거 지금은 안쓴데... 근데 혹시나 싶어서 남겨둠.
// by rtsummit
bool CItem::IsNewMountItem()
{
switch(GetVnum())
{
case 76000: case 76001: case 76002: case 76003:
case 76004: case 76005: case 76006: case 76007:
case 76008: case 76009: case 76010: case 76011:
case 76012: case 76013: case 76014:
return true;
}
return false;
}void CItem::SetAccessorySocketExpireEvent(LPEVENT pkEvent)
{
m_pkAccessorySocketExpireEvent = pkEvent;
}void CItem::AccessorySocketDegrade()
{
if (GetAccessorySocketGrade() > 0)
{
LPCHARACTER ch = GetOwner();if (ch)
{
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s에 박혀있던 보석이 사라집니다."), GetName());
}ModifyPoints(false);
SetAccessorySocketGrade(GetAccessorySocketGrade()-1);
ModifyPoints(true);int iDownTime = aiAccessorySocketDegradeTime[GetAccessorySocketGrade()];
if (test_server)
iDownTime /= 60;SetAccessorySocketDownGradeTime(iDownTime);
if (iDownTime)
StartAccessorySocketExpireEvent();
}
}// ring에 item을 박을 수 있는지 여부를 체크해서 리턴
static const bool CanPutIntoRing(LPITEM ring, LPITEM item)
{
//const DWORD vnum = item->GetVnum();
return false;
}bool CItem::CanPutInto(LPITEM item)
{
if (item->GetType() == ITEM_BELT)
return this->GetSubType() == USE_PUT_INTO_BELT_SOCKET;else if(item->GetType() == ITEM_RING)
return CanPutIntoRing(item, this);else if (item->GetType() != ITEM_ARMOR)
return false;DWORD vnum = item->GetVnum();
struct JewelAccessoryInfo
{
DWORD jewel;
DWORD wrist;
DWORD neck;
DWORD ear;
};
const static JewelAccessoryInfo infos[] = {
{ 50634, 14420, 16220, 17220 },
{ 50635, 14500, 16500, 17500 },
{ 50636, 14520, 16520, 17520 },
{ 50637, 14540, 16540, 17540 },
{ 50638, 14560, 16560, 17560 },
{ 50639, 14570, 16570, 17570 },
};DWORD item_type = (item->GetVnum() / 10) * 10;
for (size_t i = 0; i < sizeof(infos) / sizeof(infos[0]); i++)
{
const JewelAccessoryInfo& info = infos;
switch(item->GetSubType())
{
case ARMOR_WRIST:
if (info.wrist == item_type)
{
if (info.jewel == GetVnum())
{
return true;
}
else
{
return false;
}
}
break;
case ARMOR_NECK:
if (info.neck == item_type)
{
if (info.jewel == GetVnum())
{
return true;
}
else
{
return false;
}
}
break;
case ARMOR_EAR:
if (info.ear == item_type)
{
if (info.jewel == GetVnum())
{
return true;
}
else
{
return false;
}
}
break;
}
}
if (item->GetSubType() == ARMOR_WRIST)
vnum -= 14000;
else if (item->GetSubType() == ARMOR_NECK)
vnum -= 16000;
else if (item->GetSubType() == ARMOR_EAR)
vnum -= 17000;
else
return false;DWORD type = vnum / 20;
if (type < 0 || type > 11)
{
type = (vnum - 170) / 20;if (50623 + type != GetVnum())
return false;
else
return true;
}
else if (item->GetVnum() >= 16210 && item->GetVnum() <= 16219)
{
if (50625 != GetVnum())
return false;
else
return true;
}
else if (item->GetVnum() >= 16230 && item->GetVnum() <= 16239)
{
if (50626 != GetVnum())
return false;
else
return true;
}return 50623 + type == GetVnum();
}// PC_BANG_ITEM_ADD
bool CItem::IsPCBangItem()
{
for (int i = 0; i < ITEM_LIMIT_MAX_NUM; ++i)
{
if (m_pProto->aLimits.bType == LIMIT_PCBANG)
return true;
}
return false;
}
// END_PC_BANG_ITEM_ADDbool CItem::CheckItemUseLevel(int nLevel)
{
for (int i = 0; i < ITEM_LIMIT_MAX_NUM; ++i)
{
if (this->m_pProto->aLimits.bType == LIMIT_LEVEL)
{
if (this->m_pProto->aLimits.lValue > nLevel) return false;
else return true;
}
}
return true;
}long CItem::FindApplyValue(BYTE bApplyType)
{
if (m_pProto == NULL)
return 0;for (int i = 0; i < ITEM_APPLY_MAX_NUM; ++i)
{
if (m_pProto->aApplies.bType == bApplyType)
return m_pProto->aApplies.lValue;
}return 0;
}void CItem::CopySocketTo(LPITEM pItem)
{
for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
{
pItem->m_alSockets = m_alSockets;
}
}int CItem::GetAccessorySocketGrade()
{
return MINMAX(0, GetSocket(0), GetAccessorySocketMaxGrade());
}int CItem::GetAccessorySocketMaxGrade()
{
return MINMAX(0, GetSocket(1), ITEM_ACCESSORY_SOCKET_MAX_NUM);
}int CItem::GetAccessorySocketDownGradeTime()
{
return MINMAX(0, GetSocket(2), aiAccessorySocketDegradeTime[GetAccessorySocketGrade()]);
}void CItem::AttrLog()
{
const char * pszIP = NULL;if (GetOwner() && GetOwner()->GetDesc())
pszIP = GetOwner()->GetDesc()->GetHostName();for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
{
if (m_alSockets)
{
#ifdef ENABLE_NEWSTUFF
if (g_iDbLogLevel>=LOG_LEVEL_MAX)
#endif
LogManager::instance().ItemLog(i, m_alSockets, 0, GetID(), "INFO_SOCKET", "", pszIP ? pszIP : "", GetOriginalVnum());
}
}for (int i = 0; i<ITEM_ATTRIBUTE_MAX_NUM; ++i)
{
int type = m_aAttr.bType;
int value = m_aAttr.sValue;if (type)
{
#ifdef ENABLE_NEWSTUFF
if (g_iDbLogLevel>=LOG_LEVEL_MAX)
#endif
LogManager::instance().ItemLog(i, type, value, GetID(), "INFO_ATTR", "", pszIP ? pszIP : "", GetOriginalVnum());
}
}
}int CItem::GetLevelLimit()
{
for (int i = 0; i < ITEM_LIMIT_MAX_NUM; ++i)
{
if (this->m_pProto->aLimits.bType == LIMIT_LEVEL)
{
return this->m_pProto->aLimits.lValue;
}
}
return 0;
}bool CItem::OnAfterCreatedItem()
{
// 아이템을 한 번이라도 사용했다면, 그 이후엔 사용 중이지 않아도 시간이 차감되는 방식
if (-1 != this->GetProto()->cLimitRealTimeFirstUseIndex)
{
// Socket1에 아이템의 사용 횟수가 기록되어 있으니, 한 번이라도 사용한 아이템은 타이머를 시작한다.
if (0 != GetSocket(1))
{
StartRealTimeExpireEvent();
}
}return true;
}
#ifdef __AUCTION__// 경매장
// window를 경매장으로 한다.bool CItem::MoveToAuction()
{
LPCHARACTER owner = GetOwner();
if (owner == NULL)
{
sys_err ("Item those owner is not exist cannot regist in auction");
return false;
}if (GetWindow() == AUCTION)
{
sys_err ("Item is already in auction.");
}SetWindow(AUCTION);
owner->SetItem(m_bCell, NULL);
Save();
ITEM_MANAGER::instance().FlushDelayedSave(this);return true;
}void CItem::CopyToRawData (TPlayerItem* new_item)
{
if (new_item != NULL)
return;new_item->id = m_dwID;
new_item->window = m_bWindow;
new_item->pos = m_bCell;
new_item->count = m_dwCount;new_item->vnum = GetVnum();
thecore_memcpy (new_item->alSockets, m_alSockets, sizeof (m_alSockets));
thecore_memcpy (new_item->aAttr, m_aAttr, sizeof (m_aAttr));new_item->owner = m_pOwner->GetPlayerID();
}
#endifbool CItem::IsDragonSoul()
{
return GetType() == ITEM_DS;
}int CItem::GiveMoreTime_Per(float fPercent)
{
if (IsDragonSoul())
{
DWORD duration = DSManager::instance().GetDuration(this);
DWORD remain_sec = GetSocket(ITEM_SOCKET_REMAIN_SEC);
DWORD given_time = fPercent * duration / 100u;
if (remain_sec == duration)
return false;
if ((given_time + remain_sec) >= duration)
{
SetSocket(ITEM_SOCKET_REMAIN_SEC, duration);
return duration - remain_sec;
}
else
{
SetSocket(ITEM_SOCKET_REMAIN_SEC, given_time + remain_sec);
return given_time;
}
}
// 우선 용혼석에 관해서만 하도록 한다.
else
return 0;
}int CItem::GiveMoreTime_Fix(DWORD dwTime)
{
if (IsDragonSoul())
{
DWORD duration = DSManager::instance().GetDuration(this);
DWORD remain_sec = GetSocket(ITEM_SOCKET_REMAIN_SEC);
if (remain_sec == duration)
return false;
if ((dwTime + remain_sec) >= duration)
{
SetSocket(ITEM_SOCKET_REMAIN_SEC, duration);
return duration - remain_sec;
}
else
{
SetSocket(ITEM_SOCKET_REMAIN_SEC, dwTime + remain_sec);
return dwTime;
}
}
// 우선 용혼석에 관해서만 하도록 한다.
else
return 0;
}
int CItem::GetDuration()
{
if(!GetProto())
return -1;for (int i=0 ; i < ITEM_LIMIT_MAX_NUM ; i++)
{
if (LIMIT_REAL_TIME == GetProto()->aLimits.bType)
return GetProto()->aLimits.lValue;
}if (GetProto()->cLimitTimerBasedOnWearIndex >= 0)
{
BYTE cLTBOWI = GetProto()->cLimitTimerBasedOnWearIndex;
return GetProto()->aLimits[cLTBOWI].lValue;
}return -1;
}bool CItem::IsSameSpecialGroup(const LPITEM item) const
{
// 서로 VNUM이 같다면 같은 그룹인 것으로 간주
if (this->GetVnum() == item->GetVnum())
return true;if (GetSpecialGroup() && (item->GetSpecialGroup() == GetSpecialGroup()))
return true;return false;
}#ifdef __CHANGE_LOOK_SYSTEM__
void CItem::SetItemLook(DWORD look)
{
m_dwLook = look;
UpdatePacket();
ITEM_MANAGER::instance().SaveSingleItem(this);
Save();
}
#endifI think you must have this files: acce.cpp and acce.h (from game>src, server source), something like that no? If so please show the acce.cpp, either way, add your item_length.h (from common, server source)
-
1
-
-
-
Fixed, both slots in the same position..
-
-
Check the code you've added, it must have something related with position (maybe in inventorywindow.py)
-
13 hours ago, Blend said:
Try this:
open uiinventory.py and find function
RefreshEquipSlotWindow(self):
and at the end of funcion (last line) paste this:
setItemVNum(item.COSTUME_SLOT_START+2, getItemVNum(item.COSTUME_SLOT_START+2), 0) Same result
-
Hey, so i was trying to put the sash on inventory window instead of costume window, but i can't make the tooltip work..
I believe it's because it's a maximum of X items on inventory window, because if i remove the belt from the inventorywindow.py it works, here's images explaining it:
With belt active:
Tooltip on costume window:
Tooltip on inventory window (no tooltip):
And now, i will comment the belt on the inventorywindow.py like this:
Costume tooltip:
Inventory window tooltip:
As you can see, the tooltip works when i "remove"/comment the belt, but with belt it does not work, BUT, i want to keep everything and if possible i want to add more things to the inventory window
Any ideas on how can i fix this please?
Any help is appreciated!
Thank you!
-
On 7/18/2019 at 10:34 PM, Ninikek said:
Hello, I have an error in the dungeons, sometimes it happens that they do not work as they should and it is something strange.
On the first floor I ask that all the monsters be killed, but when all the monsters die nothing happens, this happens sometimes, other times it works as it should and goes to the next floor.
When the problem happens, the dungeon stops, the player is not ejected but does not continue in any way, it just stops working.
Payment to anyone who can help me correct the error.
The dungeon uses d.new_jump and several people enter at the same time.
First floor of the dungeon:
when duratus_dungeon_wave_kill.server_timer begin
local settings = duratus_dungeon.settings()
if d.select(get_server_timer_arg()) then
if d.getf("duratus_dungeon_level") == 2 then
if d.count_monster() <= 10 then
clear_server_timer("duratus_dungeon_wave_kill", get_server_timer_arg())
d.setf("duratus_dungeon_level", 3)
d.notice("Destroy all metin stones")
d.regen_file("data/dungeon/duratus_dungeon/regen_1b.txt")
else
d.notice(string.format("You still have to defeat %d monsters to move on.", d.count_monster()));
end
end
end
endI pay for the fix, thanks
If you could post the whole quest that'd be great, but, meanwhile, either try with a loop that's called like every 10 seconds or every "X" seconds and check if the monsters are killed OR when a monster dies and it's the dungeon map index (i can provide you a function to check it, it's easy to make..) and check if the monsters killed are the number that you wanted, if not, just increase the count and store it on a dungeon variable (d.setf and d.getf).
Related to what could be wrong with your code:
With that little code, maybe you are calling that only one time for example after 10 seconds, and you had to kill 3 monsters and you only killed 2.. That piece of code would never be called again, even if you kill 100 monsters with the /m command, it might work sometimes if you kill the monsters fast enough to get less than 11 monsters and keep going on the jungle stages!
Let me know if i helped or if you need anything else.
-
Fixed it, it was on dum_proto source, i had to put the bonus on the position 92 and it was on the 95 because of wolfman bonuses/resistances, i do not know why that affects that way, but that's the solution, you may now close the topic!
-
On 7/18/2019 at 9:06 AM, Traceur3RUN said:
i added full code after channge to main post, everything is 1:1 to this tutorial
can you help me? i use the same quest from this thread.
In the quest, you are sending the itemVnum to the Ride function and 0 remaining time, this means you are mounting for 0 seconds i believe, try to put something like 60, it should be mounting for 1 minute, then if it works, you can play with the value however you like
You have this when you use the item:
ride.Ride(item.vnum, 0)
And you have this when you login:
local vnum, remain_time = pc.get_special_ride_vnum()if 0 != vnum then
ride.Ride(vnum, remain_time)
endMaybe you can use the same method instead of forcing the time
-
On 7/11/2019 at 7:57 AM, promistatus said:
Hello, my sash ingame is no longer displayed it goes in the sash sloz but it is invisible does anyone have an idea why?
Error:
0711 00:26:11016 :: Set Sash 65001 to scale 0.750000 0.750000 0.750000 and pos = 0.000000 0.000000 30.000000 for job 3, sex 1
If you have the right models and the right paths, it could be from the item_scale.txt
-
If you need the encoding it's Corean > EUC-KR
-
To fix the position it's easy:
{"index":COSTUME_START_INDEX+2, "x":13, "y":126, "width":32, "height":32},#마운트 {"index":COSTUME_START_INDEX+3, "x":62, "y":126, "width":32, "height":32},#악세서리
on this too, just change the "x" with the other.
About summoning the mount when you use it, you will need to search when you use the item and equip it, the part where it's calling the mount you can have done something wrong.
It could also be something with the riding quests if you do not have the mount like horse system.
-
On 7/16/2019 at 3:12 PM, Torres said:
@useless69
I tried using another player table. SQL, same as before!
it has to be the character set has useless69 said, it doesn't matter if you use another tables, if it does not have the right character set for that "word"/name, it will keep giving you this error
-
Hey, so i was adding new bonuses on my server, one of them beeing resistance against monster, and i wanted to use a NEW bonus, not editing one that already exists.
So here's my bug:
If i switch/add the bonuses, the bonus comes fine like this: https://metin2.download/picture/HV5yVC1dIArwL4380NA5U60b7X6S6gu3/.png
But when i try to add it on item_proto, the bonus comes like this: https://metin2.download/picture/uJPw1se4fD9eCfJJP4lLgtI78Ul4g2Jm/.png
( i'm not able to upload images, i do not know why so it has to be a link)
What am i doing wrong? I've checked the name of the bonus and everything was ok, i do not get it >.<
Any help is appreciated!
Thank you in advance.
-
20 hours ago, Tatsuya said:
The traceback error is solved (that's why I marked the post as so), but my client is still crashing. That's what I'm doing right now: going file by file in root/locale to check where the error is. But thank you for your answer. I'll probably update this post (and say clearly where was the error) when I get this solved.
Good Luck, anything you need let me know
-
Debug and found a solution, i do not know if this happens any other time, but, for now, i fixed it.
It was a bug on do_ride function in cmd_general.cpp
old code that was changed:
Spoiler
for (int i = 0; i < INVENTORY_MAX_NUM; ++i)
{
LPITEM item = ch->GetInventoryItem(i);
if (NULL == item)
continue;if (item->GetType() == ITEM_COSTUME && item->GetSubType() == COSTUME_MOUNT) {
ch->UseItem(TItemPos (INVENTORY, i));
return;
}
}new code i changed:
Spoiler
for (long int i = 0; i < INVENTORY_MAX_NUM; ++i)
{
LPITEM item = ch->GetInventoryItem(i);
if (NULL == item)
continue;if (item->GetType() == ITEM_COSTUME && item->GetSubType() == COSTUME_MOUNT) {
ch->UseItem(TItemPos (INVENTORY, i));
return;
}
}Since i added more inventories i needed to check this right there!
it was from slot 0 to 255 and 8 inventories like i have, are 360 slots. So, if i did not had a mount in inventory it would check slots higher than 255 and crashed the game.
The same applied if i had the mount seal on slots higher than 255!
Problem solved atleast for now!
Thank you
-
On 6/21/2019 at 3:55 AM, Tatsuya said:
Hello,
I'm new to this world of Metin2 Dev so this may look like a silly question, excuse me for that.
Well, since I'm getting started, I'm starting to learn how to implement some systems. I'm starting with Sash System by LeNnT. I changed everything I had to, built an .exe and, when I ran it, it was giving me an indentation error. I fixed it, however. Sadly, it's now giving me this "traceback error" (as you can see in spoiler).
In 'syserr' .txt file, is written "RunMain Error", but I don't know how to interpret that. I tried to search for a solution and couldn't find anything helpful, so I was wondering if some of you guys could help me to fix the error.
Thank you by advance,
Tatsuya
Hey, i believe i had that thing too when i tried to install that system, i think that must be somewhere around what you did on client side, on pack, maybe on root/locale. I don't know more than that, try to start the client on a backup before you installed the system and see if it works, if it does, you need to change file by file until you check where's the error
Edit:
-- I just read it's solved but if anyone has the same problem might be a solution xb --
-
On 6/12/2019 at 12:20 AM, Jinlee said:
Hi. I saw this tutorial
But i don't wanna extend all items. I just wanna extend bonus changer to 2000 instead of 200. Can someone tell me how to do it ?
Search on google: metin2 max yang 999t+
I believe we cannot post links of other forums, if you want a link you can pm me asking for it
-
On 6/22/2019 at 10:39 AM, cubex3 said:
Now everything works but I can't get the items out of the slot and the item description will be shown after 3sec only.
if I keep the cursor on the shining item.
I would be happy if you could give me an approach to the solution or even directly the solution.
Also pay a small fee who can fix this for me quickly.Syserr is clean?
Did you change the size of the window on costumewindow.py?
Did you make any change on uitooltip.py?
-
-
Hey! Here's an example:
when 9003.chat."start timer" begin
timer("your_timer_name", 60)
end
when your_timer_name.timer begin
--Do something
end1 minute timer after you press "start timer" on general store
-
19 hours ago, OnlyRipper said:
1)
I'm concerned about this in particular.
INSERT DELAYED INTO log (type, time, who, x, y, what, how, hint, ip) VALUES('CHARACTER', NOW(), 10002, 954319, 261200, 0, 'LOGIN', '192.168.1.8 1997735000 1 41 200000', '192.168.1.8')
Because:
ChildLoop: AsyncSQL: query failed: Data too long for column 'hint' at row 1
2)
SYSERR: Jun 20 19:21:35.356706 :: ItemLoad: cannot create item by vnum 49000 (name Display id 10000001)
You have a valid item by vnum 49000?(and others with the same error pattern)
3)
0620 18:23:14559 :: CDungeonBlock::Load(filename=d:/ymir work/zone/dungeon/resources picking zon/mushroom01.gr2) - model count is 0
Replace the file with another from another server file or client.See if it's working.This should be first step.
Fixed all those errors, i managed to find a pattern, everytime i try to mount i mean, CTRL+G without a mount seal on my inventory or without horse called, this happens.
I don't know if this happens in other situations, but i managed to find that one in particular, i rebooted the server 3 times and tested this 3 times. Everytime the channel got bugged!
Will try to to a debug on this and post more info later!
Thank you for your feedback guys!
Thief glove - ingame time
in Community Support - Questions & Answers
Posted
A "work around" is to add time to the thiefs glove base on the last login and current date, you can add time to it, but it can have some fails in the middle if not done properly