newhere 0 Posted August 19, 2019 Share Posted August 19, 2019 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: Spoiler #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));#endif d->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_GROUNDconst 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;}#endif void 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)#elsebool 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;#endif if (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; }#endif if (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_INVENTORYbool CItem::EquipTo(LPCHARACTER ch, WORD bWearCell)#elsebool 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);#endif if (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);#endif m_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_LIMITlong long CItem::GetGold()#elseint 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_LIMITlong long CItem::GetShopBuyPrice()#elseint 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 1 int 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 rtsummitbool 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_ADDbool 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_ADD bool 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();}#endif bool 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();}#endif item.cpp Link to comment Share on other sites More sharing options...
displayjokes 89 Posted August 19, 2019 Share Posted August 19, 2019 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: Reveal hidden contents #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));#endif d->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_GROUNDconst 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;}#endif void 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)#elsebool 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;#endif if (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; }#endif if (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_INVENTORYbool CItem::EquipTo(LPCHARACTER ch, WORD bWearCell)#elsebool 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);#endif if (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);#endif m_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_LIMITlong long CItem::GetGold()#elseint 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_LIMITlong long CItem::GetShopBuyPrice()#elseint 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 1 int 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 rtsummitbool 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_ADDbool 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_ADD bool 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();}#endif bool 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();}#endif item.cpp I 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 It's all lies Link to comment Share on other sites More sharing options...
newhere 0 Posted August 20, 2019 Author Share Posted August 20, 2019 hey, thanks for your answer. i dont have acce.cpp or acce.h item_lenght.h Spoiler #ifndef __INC_METIN2_ITEM_LENGTH_H__ #define __INC_METIN2_ITEM_LENGTH_H__ #include "CommonDefines.h" enum EItemMisc { ITEM_NAME_MAX_LEN = 24, ITEM_VALUES_MAX_NUM = 6, ITEM_SMALL_DESCR_MAX_LEN = 256, ITEM_LIMIT_MAX_NUM = 2, ITEM_APPLY_MAX_NUM = 3, ITEM_SOCKET_MAX_NUM = 3, ITEM_MAX_COUNT = 200, ITEM_ATTRIBUTE_NORM_NUM = 5, ITEM_ATTRIBUTE_RARE_NUM = 2, ITEM_ATTRIBUTE_NORM_START = 0, ITEM_ATTRIBUTE_NORM_END = ITEM_ATTRIBUTE_NORM_START + ITEM_ATTRIBUTE_NORM_NUM, ITEM_ATTRIBUTE_RARE_START = ITEM_ATTRIBUTE_NORM_END, ITEM_ATTRIBUTE_RARE_END = ITEM_ATTRIBUTE_RARE_START + ITEM_ATTRIBUTE_RARE_NUM, ITEM_ATTRIBUTE_MAX_NUM = ITEM_ATTRIBUTE_RARE_END, // 7 ITEM_ATTRIBUTE_MAX_LEVEL = 5, ITEM_AWARD_WHY_MAX_LEN = 50, REFINE_MATERIAL_MAX_NUM = 5, ITEM_ELK_VNUM = 50026, #ifdef __COSTUME_ACCE__ ITEM_MAX_ACCEDRAIN = 25, ITEM_MIN_ACCEDRAIN = 20, #endif }; const BYTE ITEM_SOCKET_REMAIN_SEC = 0; enum EItemValueIdice { ITEM_VALUE_DRAGON_SOUL_POLL_OUT_BONUS_IDX = 0, ITEM_VALUE_CHARGING_AMOUNT_IDX = 0, ITEM_VALUE_SECONDARY_COIN_UNIT_IDX = 0, }; enum EItemDragonSoulSockets { ITEM_SOCKET_DRAGON_SOUL_ACTIVE_IDX = 2, ITEM_SOCKET_CHARGING_AMOUNT_IDX = 2, }; // 헐 이거 미친거 아니야? // 나중에 소켓 확장하면 어쩌려고 이지랄 -_-;;; enum EItemUniqueSockets { ITEM_SOCKET_UNIQUE_SAVE_TIME = ITEM_SOCKET_MAX_NUM - 2, ITEM_SOCKET_UNIQUE_REMAIN_TIME = ITEM_SOCKET_MAX_NUM - 1 }; enum EItemTypes { ITEM_NONE, //0 ITEM_WEAPON, //1//무기 ITEM_ARMOR, //2//갑옷 ITEM_USE, //3//아이템 사용 ITEM_AUTOUSE, //4 ITEM_MATERIAL, //5 ITEM_SPECIAL, //6 //스페셜 아이템 ITEM_TOOL, //7 ITEM_LOTTERY, //8//복권 ITEM_ELK, //9//돈 ITEM_METIN, //10 ITEM_CONTAINER, //11 ITEM_FISH, //12//낚시 ITEM_ROD, //13 ITEM_RESOURCE, //14 ITEM_CAMPFIRE, //15 ITEM_UNIQUE, //16 ITEM_SKILLBOOK, //17 ITEM_QUEST, //18 ITEM_POLYMORPH, //19 ITEM_TREASURE_BOX, //20//보물상자 ITEM_TREASURE_KEY, //21//보물상자 열쇠 ITEM_SKILLFORGET, //22 ITEM_GIFTBOX, //23 ITEM_PICK, //24 ITEM_HAIR, //25//머리 ITEM_TOTEM, //26//토템 ITEM_BLEND, //27//생성될때 랜덤하게 속성이 붙는 약물 ITEM_COSTUME, //28//코스츔 아이템 (2011년 8월 추가된 코스츔 시스템용 아이템) ITEM_DS, //29 //용혼석 ITEM_SPECIAL_DS, //30 // 특수한 용혼석 (DS_SLOT에 착용하는 UNIQUE 아이템이라 생각하면 됨) ITEM_EXTRACT, //31 추출도구. ITEM_SECONDARY_COIN, //32 ?? 명도전?? ITEM_RING, //33 반지 ITEM_BELT, //34 벨트 #ifdef COMPANION_SYSTEM ITEM_COMPANION, #endif #ifdef SHININGSYSTEM ITEM_SHINING, //36 벨트 #endif }; enum EMetinSubTypes { METIN_NORMAL, METIN_GOLD, }; enum EWeaponSubTypes { WEAPON_SWORD, WEAPON_DAGGER, WEAPON_BOW, WEAPON_TWO_HANDED, WEAPON_BELL, WEAPON_FAN, WEAPON_ARROW, WEAPON_MOUNT_SPEAR, #ifdef ENABLE_WOLFMAN_CHARACTER WEAPON_CLAW, #endif WEAPON_NUM_TYPES, }; enum EArmorSubTypes { ARMOR_BODY, ARMOR_HEAD, ARMOR_SHIELD, ARMOR_WRIST, ARMOR_FOOTS, ARMOR_NECK, ARMOR_EAR, ARMOR_NUM_TYPES }; enum ECostumeSubTypes { COSTUME_BODY = ARMOR_BODY, // [중요!!] ECostumeSubTypes enum value는 종류별로 EArmorSubTypes의 그것과 같아야 함. COSTUME_HAIR = ARMOR_HEAD, // 이는 코스츔 아이템에 추가 속성을 붙이겠다는 사업부의 요청에 따라서 기존 로직을 활용하기 위함임. #ifdef __COSTUME_ACCE__ COSTUME_ACCE, #endif #ifdef ENABLE_MOUNT_COSTUME_SYSTEM COSTUME_MOUNT = 3, #endif #ifdef ENABLE_WEAPON_COSTUME_SYSTEM COSTUME_WEAPON = 4, #endif COSTUME_NUM_TYPES, }; #ifdef __COSTUME_ACCE__ enum { ABSORB, COMBINE, }; enum { ACCE_SLOT_LEFT, ACCE_SLOT_RIGHT, ACCE_SLOT_RESULT, ACCE_SLOT_MAX_NUM, }; #endif enum EDragonSoulSubType { DS_SLOT1, DS_SLOT2, DS_SLOT3, DS_SLOT4, DS_SLOT5, DS_SLOT6, DS_SLOT_MAX, }; enum EDragonSoulGradeTypes { DRAGON_SOUL_GRADE_NORMAL, DRAGON_SOUL_GRADE_BRILLIANT, DRAGON_SOUL_GRADE_RARE, DRAGON_SOUL_GRADE_ANCIENT, DRAGON_SOUL_GRADE_LEGENDARY, DRAGON_SOUL_GRADE_MAX, }; enum EDragonSoulStepTypes { DRAGON_SOUL_STEP_LOWEST, DRAGON_SOUL_STEP_LOW, DRAGON_SOUL_STEP_MID, DRAGON_SOUL_STEP_HIGH, DRAGON_SOUL_STEP_HIGHEST, DRAGON_SOUL_STEP_MAX, }; #define DRAGON_SOUL_STRENGTH_MAX 7 enum EDSInventoryMaxNum { DRAGON_SOUL_INVENTORY_MAX_NUM = DS_SLOT_MAX * DRAGON_SOUL_GRADE_MAX * DRAGON_SOUL_BOX_SIZE, }; #ifdef SHININGSYSTEM enum EShiningSubTypes { SHINING_WEAPON, SHINING_ARMOR, SHINING_SPECIAL, }; #endif enum EFishSubTypes { FISH_ALIVE, FISH_DEAD, }; enum EResourceSubTypes { RESOURCE_FISHBONE, RESOURCE_WATERSTONEPIECE, RESOURCE_WATERSTONE, RESOURCE_BLOOD_PEARL, RESOURCE_BLUE_PEARL, RESOURCE_WHITE_PEARL, RESOURCE_BUCKET, RESOURCE_CRYSTAL, RESOURCE_GEM, RESOURCE_STONE, RESOURCE_METIN, RESOURCE_ORE, }; enum EUniqueSubTypes { UNIQUE_NONE, UNIQUE_BOOK, UNIQUE_SPECIAL_RIDE, UNIQUE_SPECIAL_MOUNT_RIDE, }; enum EUseSubTypes { USE_POTION, // 0 USE_TALISMAN, USE_TUNING, USE_MOVE, USE_TREASURE_BOX, USE_MONEYBAG, USE_BAIT, USE_ABILITY_UP, USE_AFFECT, USE_CREATE_STONE, USE_SPECIAL, // 10 USE_POTION_NODELAY, USE_CLEAR, USE_INVISIBILITY, USE_DETACHMENT, USE_BUCKET, USE_POTION_CONTINUE, USE_CLEAN_SOCKET, USE_CHANGE_ATTRIBUTE, USE_ADD_ATTRIBUTE, USE_ADD_ACCESSORY_SOCKET, // 20 USE_PUT_INTO_ACCESSORY_SOCKET, USE_ADD_ATTRIBUTE2, USE_RECIPE, USE_CHANGE_ATTRIBUTE2, USE_BIND, USE_UNBIND, USE_TIME_CHARGE_PER, USE_TIME_CHARGE_FIX, // 28 USE_PUT_INTO_BELT_SOCKET, // 29 벨트 소켓에 사용할 수 있는 아이템 USE_PUT_INTO_RING_SOCKET, // 30 반지 소켓에 사용할 수 있는 아이템 (유니크 반지 말고, 새로 추가된 반지 슬롯) USE_CHANGE_COSTUME_ATTR, // 31 USE_RESET_COSTUME_ATTR, // 32 #ifdef __CHANGE_LOOK_SYSTEM__ USE_RESET_LOOK_VNUM, #endif }; enum EExtractSubTypes { EXTRACT_DRAGON_SOUL, EXTRACT_DRAGON_HEART, }; enum EAutoUseSubTypes { AUTOUSE_POTION, AUTOUSE_ABILITY_UP, AUTOUSE_BOMB, AUTOUSE_GOLD, AUTOUSE_MONEYBAG, AUTOUSE_TREASURE_BOX }; enum EMaterialSubTypes { MATERIAL_LEATHER, MATERIAL_BLOOD, MATERIAL_ROOT, MATERIAL_NEEDLE, MATERIAL_JEWEL, MATERIAL_DS_REFINE_NORMAL, MATERIAL_DS_REFINE_BLESSED, MATERIAL_DS_REFINE_HOLLY, }; enum ESpecialSubTypes { SPECIAL_MAP, SPECIAL_KEY, SPECIAL_DOC, SPECIAL_SPIRIT, }; enum EToolSubTypes { TOOL_FISHING_ROD }; enum ELotterySubTypes { LOTTERY_TICKET, LOTTERY_INSTANT }; enum EItemFlag { ITEM_FLAG_REFINEABLE = (1 << 0), ITEM_FLAG_SAVE = (1 << 1), ITEM_FLAG_STACKABLE = (1 << 2), // 여러개 합칠 수 있음 ITEM_FLAG_COUNT_PER_1GOLD = (1 << 3), ITEM_FLAG_SLOW_QUERY = (1 << 4), ITEM_FLAG_UNUSED01 = (1 << 5), // UNUSED ITEM_FLAG_UNIQUE = (1 << 6), ITEM_FLAG_MAKECOUNT = (1 << 7), ITEM_FLAG_IRREMOVABLE = (1 << 8), ITEM_FLAG_CONFIRM_WHEN_USE = (1 << 9), ITEM_FLAG_QUEST_USE = (1 << 10), ITEM_FLAG_QUEST_USE_MULTIPLE = (1 << 11), ITEM_FLAG_QUEST_GIVE = (1 << 12), ITEM_FLAG_LOG = (1 << 13), ITEM_FLAG_APPLICABLE = (1 << 14), }; enum EItemAntiFlag { ITEM_ANTIFLAG_FEMALE = (1 << 0), // 여성 사용 불가 ITEM_ANTIFLAG_MALE = (1 << 1), // 남성 사용 불가 ITEM_ANTIFLAG_WARRIOR = (1 << 2), // 무사 사용 불가 ITEM_ANTIFLAG_ASSASSIN = (1 << 3), // 자객 사용 불가 ITEM_ANTIFLAG_SURA = (1 << 4), // 수라 사용 불가 ITEM_ANTIFLAG_SHAMAN = (1 << 5), // 무당 사용 불가 ITEM_ANTIFLAG_GET = (1 << 6), // 집을 수 없음 ITEM_ANTIFLAG_DROP = (1 << 7), // 버릴 수 없음 ITEM_ANTIFLAG_SELL = (1 << 8), // 팔 수 없음 ITEM_ANTIFLAG_EMPIRE_A = (1 << 9), // A 제국 사용 불가 ITEM_ANTIFLAG_EMPIRE_B = (1 << 10), // B 제국 사용 불가 ITEM_ANTIFLAG_EMPIRE_C = (1 << 11), // C 제국 사용 불가 ITEM_ANTIFLAG_SAVE = (1 << 12), // 저장되지 않음 ITEM_ANTIFLAG_GIVE = (1 << 13), // 거래 불가 ITEM_ANTIFLAG_PKDROP = (1 << 14), // PK시 떨어지지 않음 ITEM_ANTIFLAG_STACK = (1 << 15), // 합칠 수 없음 ITEM_ANTIFLAG_MYSHOP = (1 << 16), // 개인 상점에 올릴 수 없음 ITEM_ANTIFLAG_SAFEBOX = (1 << 17), // 창고에 넣을 수 없음 #ifdef ENABLE_WOLFMAN_CHARACTER ITEM_ANTIFLAG_WOLFMAN = (1 << 18), // 수인족 사용 불가 #endif }; enum EItemWearableFlag { WEARABLE_BODY = (1 << 0), WEARABLE_HEAD = (1 << 1), WEARABLE_FOOTS = (1 << 2), WEARABLE_WRIST = (1 << 3), WEARABLE_WEAPON = (1 << 4), WEARABLE_NECK = (1 << 5), WEARABLE_EAR = (1 << 6), WEARABLE_UNIQUE = (1 << 7), WEARABLE_SHIELD = (1 << 8), WEARABLE_ARROW = (1 << 9), WEARABLE_HAIR = (1 << 10), WEARABLE_ABILITY = (1 << 11), WEARABLE_COSTUME_BODY = (1 << 12), }; enum ELimitTypes { LIMIT_NONE, LIMIT_LEVEL, LIMIT_STR, LIMIT_DEX, LIMIT_INT, LIMIT_CON, LIMIT_PCBANG, /// 착용 여부와 상관 없이 실시간으로 시간 차감 (socket0에 소멸 시간이 박힘: unix_timestamp 타입) LIMIT_REAL_TIME, /// 아이템을 맨 처음 사용(혹은 착용) 한 순간부터 리얼타임 타이머 시작 /// 최초 사용 전에는 socket0에 사용가능시간(초단위, 0이면 프로토의 limit value값 사용) 값이 쓰여있다가 /// 아이템 사용시 socket1에 사용 횟수가 박히고 socket0에 unix_timestamp 타입의 소멸시간이 박힘. LIMIT_REAL_TIME_START_FIRST_USE, /// 아이템을 착용 중일 때만 사용 시간이 차감되는 아이템 /// socket0에 남은 시간이 초단위로 박힘. (아이템 최초 사용시 해당 값이 0이면 프로토의 limit value값을 socket0에 복사) LIMIT_TIMER_BASED_ON_WEAR, LIMIT_MAX_NUM }; enum EAttrAddonTypes { ATTR_ADDON_NONE, // positive values are reserved for set ATTR_DAMAGE_ADDON = -1, }; enum ERefineType { REFINE_TYPE_NORMAL, REFINE_TYPE_NOT_USED1, REFINE_TYPE_SCROLL, REFINE_TYPE_HYUNIRON, REFINE_TYPE_MONEY_ONLY, REFINE_TYPE_MUSIN, REFINE_TYPE_BDRAGON, }; #endif item_length.h Link to comment Share on other sites More sharing options...
Premium Hunger 472 Posted August 20, 2019 Premium Share Posted August 20, 2019 Item_max_acce_drain 1 Link to comment Share on other sites More sharing options...
newhere 0 Posted August 20, 2019 Author Share Posted August 20, 2019 thanks for your answer. but i dont know. i have like this: ITEM_MAX_ACCEDRAIN = 25, ITEM_MIN_ACCEDRAIN = 20, References Spoiler if ((pBaseItem->GetRefinedVnum() == 0) && (pBaseItem->GetSocket(0) < ITEM_MAX_ACCEDRAIN) && (GetAcceRefineGrade(pBaseItem->GetVnum()) == 4)) { if (pBaseItem->GetSocket(0) < ITEM_MIN_ACCEDRAIN) { ChatPacket(CHAT_TYPE_INFO, LC_TEXT("ACCE_COMBINE_ABSORB_TO_LOW")); return; } uppMax = true; result_vnum = pBaseItem->GetVnum(); } else { result_vnum = pBaseItem->GetRefinedVnum(); } Link to comment Share on other sites More sharing options...
Premium Hunger 472 Posted August 20, 2019 Premium Share Posted August 20, 2019 Item max acce drain is the max perc. you get if you combine two custom sash and item min max acce drain is the minimum perc. Now, you are asking the sash to drain more than 25% of an item and you have ITEM_MAX_ACCEDRAIN = 25, what you gonna do? Link to comment Share on other sites More sharing options...
newhere 0 Posted August 20, 2019 Author Share Posted August 20, 2019 thanks for help but my problem was that the sash absorbs 100% of the bonus not like 25%. "Its absorbing the 100% of the 1/5 and 6/7 Bonus." Link to comment Share on other sites More sharing options...
displayjokes 89 Posted August 20, 2019 Share Posted August 20, 2019 2 minutes ago, newhere said: thanks for help but my problem was that the sash absorbs 100% of the bonus not like 25%. "Its absorbing the 100% of the 1/5 and 6/7 Bonus." Where do you have the sash functions? It's not on item.cpp that you posted if i'm not blind xD 1 It's all lies Link to comment Share on other sites More sharing options...
newhere 0 Posted August 20, 2019 Author Share Posted August 20, 2019 I have no calculation for 1/5 and 6/7 bonus they just add to the sash like in the weapon. no function for calculation. so i need to find the item attribute add to sash thing and write it like if 25% sash item_attr /100*25 i think. Link to comment Share on other sites More sharing options...
displayjokes 89 Posted August 20, 2019 Share Posted August 20, 2019 8 minutes ago, newhere said: I have no calculation for 1/5 and 6/7 bonus they just add to the sash like in the weapon. no function for calculation. so i need to find the item attribute add to sash thing and write it like if 25% sash item_attr /100*25 i think. Show me the functions where the absorptions happens and we can see where's the problem 1 It's all lies Link to comment Share on other sites More sharing options...
newhere 0 Posted August 20, 2019 Author Share Posted August 20, 2019 maybe here: if (ABSORB == GetAcceWindowType()) Spoiler if (ABSORB == GetAcceWindowType()) { if (m_pointsInstant.pAcceSlots[ACCE_SLOT_RIGHT] != WORD_MAX && m_pointsInstant.pAcceSlots[ACCE_SLOT_LEFT] != WORD_MAX) { LPITEM pkAcce = GetItem(TItemPos(INVENTORY, m_pointsInstant.pAcceSlots[ACCE_SLOT_LEFT])); LPITEM pkWeaponToAbsorb = GetItem(TItemPos(INVENTORY, m_pointsInstant.pAcceSlots[ACCE_SLOT_RIGHT])); LPITEM pShowItem = ITEM_MANAGER::instance().CreateItem(pkAcce->GetVnum(), 1, 0, false, -1, true); pkWeaponToAbsorb->CopyAttributeTo(pShowItem); pShowItem->SetSocket(0, pkAcce->GetSocket(0)); pShowItem->SetSocket(1, pkWeaponToAbsorb->GetVnum()); TPacketGCAcce pack; pack.header = HEADER_GC_ACCE; pack.subheader = ACCE_SUBHEADER_GC_SET_ITEM; pack.size = sizeof(TPacketGCAcce) + sizeof(TPacketGCItemSet); TPacketGCItemSet pack_sub; pack_sub.header = 0; pack_sub.Cell = TItemPos(ACCEREFINE, (WORD)ACCE_SLOT_RESULT); pack_sub.vnum = pShowItem->GetVnum(); pack_sub.count = (BYTE)pShowItem->GetCount(); pack_sub.flags = pShowItem->GetFlag(); pack_sub.anti_flags = pShowItem->GetAntiFlag(); thecore_memcpy(pack_sub.alSockets, pShowItem->GetSockets(), sizeof(pack_sub.alSockets)); thecore_memcpy(pack_sub.aAttr, pShowItem->GetAttributes(), sizeof(pack_sub.aAttr)); GetDesc()->BufferedPacket(&pack, sizeof(TPacketGCAcce)); GetDesc()->Packet(&pack_sub, sizeof(TPacketGCItemSet)); M2_DESTROY_ITEM(pShowItem); } char_item.cpp Link to comment Share on other sites More sharing options...
displayjokes 89 Posted August 20, 2019 Share Posted August 20, 2019 22 minutes ago, newhere said: maybe here: if (ABSORB == GetAcceWindowType()) Reveal hidden contents if (ABSORB == GetAcceWindowType()) { if (m_pointsInstant.pAcceSlots[ACCE_SLOT_RIGHT] != WORD_MAX && m_pointsInstant.pAcceSlots[ACCE_SLOT_LEFT] != WORD_MAX) { LPITEM pkAcce = GetItem(TItemPos(INVENTORY, m_pointsInstant.pAcceSlots[ACCE_SLOT_LEFT])); LPITEM pkWeaponToAbsorb = GetItem(TItemPos(INVENTORY, m_pointsInstant.pAcceSlots[ACCE_SLOT_RIGHT])); LPITEM pShowItem = ITEM_MANAGER::instance().CreateItem(pkAcce->GetVnum(), 1, 0, false, -1, true); pkWeaponToAbsorb->CopyAttributeTo(pShowItem); pShowItem->SetSocket(0, pkAcce->GetSocket(0)); pShowItem->SetSocket(1, pkWeaponToAbsorb->GetVnum()); TPacketGCAcce pack; pack.header = HEADER_GC_ACCE; pack.subheader = ACCE_SUBHEADER_GC_SET_ITEM; pack.size = sizeof(TPacketGCAcce) + sizeof(TPacketGCItemSet); TPacketGCItemSet pack_sub; pack_sub.header = 0; pack_sub.Cell = TItemPos(ACCEREFINE, (WORD)ACCE_SLOT_RESULT); pack_sub.vnum = pShowItem->GetVnum(); pack_sub.count = (BYTE)pShowItem->GetCount(); pack_sub.flags = pShowItem->GetFlag(); pack_sub.anti_flags = pShowItem->GetAntiFlag(); thecore_memcpy(pack_sub.alSockets, pShowItem->GetSockets(), sizeof(pack_sub.alSockets)); thecore_memcpy(pack_sub.aAttr, pShowItem->GetAttributes(), sizeof(pack_sub.aAttr)); GetDesc()->BufferedPacket(&pack, sizeof(TPacketGCAcce)); GetDesc()->Packet(&pack_sub, sizeof(TPacketGCItemSet)); M2_DESTROY_ITEM(pShowItem); } char_item.cpp if you comment this line and absorb a weapon, does the sash gain attributtes or no? comment this and try: pkWeaponToAbsorb->CopyAttributeTo(pShowItem); If it does not gain any atribute we can do a workaround, setting the attributes by ourselves It's all lies Link to comment Share on other sites More sharing options...
Recommended Posts
Please sign in to comment
You will be able to leave a comment after signing in
Sign In Now