// Remove item from bucket without memory delete // Returns item pointer if full delete was successful ItemInst* Inventory::PopItem(int16 slot_id) { ItemInst* p = nullptr; if (slot_id == SLOT_CURSOR) { // Cursor p = m_cursor.pop(); } else if ((slot_id >= 1 && slot_id <= 21)) { // Worn slots p = m_worn[slot_id]; m_worn.erase(slot_id); } else if ((slot_id >= 22 && slot_id <= 29)) { p = m_inv[slot_id]; m_inv.erase(slot_id); } else if (slot_id >= 2000 && slot_id <= 2007) { // Bank slots p = m_bank[slot_id]; m_bank.erase(slot_id); } else if (slot_id >= 3000 && slot_id <= 3007) { // Trade window slots p = m_trade[slot_id]; m_trade.erase(slot_id); } else { // Is slot inside bag? ItemInst* baginst = GetItem(Inventory::CalcSlotId(slot_id)); if (baginst != nullptr && baginst->IsType(ItemClassContainer)) { p = baginst->PopItem(Inventory::CalcBagIdx(slot_id)); } } // Return pointer that needs to be deleted (or otherwise managed) return p; }
Object::Object(const char *model, float x, float y, float z, float heading, uint8 type, uint32 decay_time) : respawn_timer(0), decay_timer(decay_time) { user = nullptr; last_user = nullptr; ItemInst* inst = nullptr; inst = new ItemInst(ItemInstWorldContainer); // Initialize members m_id = 0; m_inst = (inst) ? inst->Clone() : nullptr; m_type = type; m_icon = 0; m_inuse = false; m_ground_spawn = false; // Set as much struct data as we can memset(&m_data, 0, sizeof(Object_Struct)); m_data.heading = heading; m_data.x = x; m_data.y = y; m_data.z = z; m_data.zone_id = zone->GetZoneID(); if (decay_time) decay_timer.Start(); respawn_timer.Disable(); if(model) strcpy(m_data.object_name, model); else strcpy(m_data.object_name, "IT64_ACTORDEF"); //default object name if model isn't specified for some unknown reason }
// Remove all items from container void ItemInst::ClearByFlags(byFlagSetting is_nodrop, byFlagSetting is_norent) { // Destroy container contents iter_contents cur, end, del; cur = m_contents.begin(); end = m_contents.end(); for (; cur != end;) { ItemInst* inst = cur->second; const Item_Struct* item = inst->GetItem(); del = cur; ++cur; switch (is_nodrop) { case byFlagSet: if (item->NoDrop == 0) { safe_delete(inst); m_contents.erase(del->first); continue; } default: break; } switch (is_norent) { case byFlagSet: if (item->NoRent == 0) { safe_delete(inst); m_contents.erase(del->first); continue; } default: break; } } }
void PlayerInst::pickup_item(GameState* gs, const GameAction& action) { const int PICKUP_RATE = 10; GameInst* inst = gs->get_instance(action.use_id); if (!inst) { return; } ItemInst* iteminst = dynamic_cast<ItemInst*>(inst); LANARTS_ASSERT(iteminst); const Item& type = iteminst->item_type(); int amnt = iteminst->item_quantity(); bool inventory_full = false; if (type.id == get_item_by_name("Gold")) { gold() += amnt; } else { itemslot_t slot = inventory().add(type); if (slot == -1) { inventory_full = true; } else if (projectile_should_autowield(equipment(), type, this->last_chosen_weaponclass)) { projectile_smart_equip(inventory(), slot); } } if (!inventory_full) { cooldowns().reset_pickup_cooldown(PICKUP_RATE); gs->remove_instance(iteminst); } }
void ItemInst::step(GameState *gs) { GameInst* other_item = NULL; ItemEntry& ientry = item.item_entry(); if (ientry.stackable && gs->object_radius_test(this, &other_item, 1, same_item_colfilter)) { ItemInst* oinst = (ItemInst*)other_item; if (oinst->item == item && id < oinst->id) { gs->remove_instance(oinst); quantity += oinst->item_quantity(); } } }
// Internal Method: "put" item into bucket, without regard for what is currently in bucket // Assumes item has already been allocated sint16 Inventory::_PutItem(sint16 slot_id, ItemInst* inst) { // If putting a NULL into slot, we need to remove slot without memory delete if (inst == NULL) { //Why do we not delete the poped item here???? PopItem(slot_id); return slot_id; } sint16 result = SLOT_INVALID; if (slot_id==SLOT_CURSOR) { // Cursor // Replace current item on cursor, if exists m_cursor.pop(); // no memory delete, clients of this function know what they are doing m_cursor.push_front(inst); result = slot_id; } else if ((slot_id>=0 && slot_id<=21) || (slot_id >= 400 && slot_id<=404) || (slot_id == 9999)) { // Worn slots m_worn[slot_id] = inst; result = slot_id; } else if ((slot_id>=22 && slot_id<=29)) { m_inv[slot_id] = inst; result = slot_id; } else if (slot_id>=2000 && slot_id<=2023) { // Bank slots m_bank[slot_id] = inst; result = slot_id; } else if (slot_id>=2500 && slot_id<=2501) { // Shared bank slots m_shbank[slot_id] = inst; result = slot_id; } else if (slot_id>=3000 && slot_id<=3007) { // Trade window slots m_trade[slot_id] = inst; result = slot_id; } else { // Slot must be within a bag ItemInst* baginst = GetItem(Inventory::CalcSlotId(slot_id)); // Get parent bag if (baginst && baginst->IsType(ItemClassContainer)) { baginst->_PutItem(Inventory::CalcBagIdx(slot_id), inst); result = slot_id; } } if (result == SLOT_INVALID) { LogFile->write(EQEMuLog::Error, "Inventory::_PutItem: Invalid slot_id specified (%i)", slot_id); safe_delete(inst); // Slot not found, clean up } return result; }
// Checks All items in a bag for No Drop bool Inventory::CheckNoDrop(sint16 slot_id) { ItemInst* inst = GetItem(slot_id); if (!inst) return false; if (!inst->GetItem()->NoDrop) return true; if (inst->GetItem()->ItemClass == 1) { for (int16 i=0; i<10; i++) { ItemInst* bagitem = GetItem(Inventory::CalcSlotId(slot_id, i)); if (bagitem && !bagitem->GetItem()->NoDrop) return true; } } return false; }
// Internal Method: Checks an inventory queue type bucket for a particular item int16 Inventory::_HasItemByLoreGroup(ItemInstQueue& iqueue, uint32 loregroup) { iter_queue it; iter_contents itb; // Read-only iteration of queue for (it = iqueue.begin(); it != iqueue.end(); ++it) { ItemInst* inst = *it; if (inst) { if (inst->GetItem()->LoreGroup == loregroup) return SLOT_CURSOR; } // Go through bag, if bag if (inst && inst->IsType(ItemClassContainer)) { for (itb = inst->_begin(); itb != inst->_end(); ++itb) { ItemInst* baginst = itb->second; if (baginst && baginst->IsType(ItemClassCommon) && baginst->GetItem()->LoreGroup == loregroup) return Inventory::CalcSlotId(SLOT_CURSOR, itb->first); } } } // Not found return SLOT_INVALID; }
int16 Inventory::_HasItemByLoreGroup(std::map<int16, ItemInst*>& bucket, uint32 loregroup) { iter_inst it; iter_contents itb; ItemInst* inst = nullptr; // Check item: After failed checks, check bag contents (if bag) for (it = bucket.begin(); it != bucket.end(); ++it) { inst = it->second; if (inst) { if (inst->GetItem()->LoreGroup == loregroup) return it->first; } // Go through bag, if bag if (inst && inst->IsType(ItemClassContainer)) { for (itb = inst->_begin(); itb != inst->_end(); ++itb) { ItemInst* baginst = itb->second; if (baginst && baginst->IsType(ItemClassCommon) && baginst->GetItem()->LoreGroup == loregroup) return Inventory::CalcSlotId(it->first, itb->first); } } } // Not found return SLOT_INVALID; }
ItemInst* GuildBankManager::GetItem(uint32 GuildID, uint16 Area, uint16 SlotID, uint32 Quantity) { std::list<GuildBank*>::iterator Iterator = GetGuildBank(GuildID); if(Iterator == Banks.end()) return nullptr; GuildBankItem* BankArea = nullptr; ItemInst* inst = nullptr; if(Area == GuildBankDepositArea) { if((SlotID > (GUILD_BANK_DEPOSIT_AREA_SIZE - 1))) return nullptr; inst = database.CreateItem((*Iterator)->Items.DepositArea[SlotID].ItemID); if(!inst) return nullptr; BankArea = &(*Iterator)->Items.DepositArea[0]; } else { if((SlotID > (GUILD_BANK_MAIN_AREA_SIZE - 1))) return nullptr; inst = database.CreateItem((*Iterator)->Items.MainArea[SlotID].ItemID); if(!inst) return nullptr; BankArea = &(*Iterator)->Items.MainArea[0]; } if(!inst->IsStackable()) inst->SetCharges(BankArea[SlotID].Quantity); else { if(Quantity <= BankArea[SlotID].Quantity) inst->SetCharges(Quantity); else inst->SetCharges(BankArea[SlotID].Quantity); } return inst; }
void Inventory::dumpItemCollection(const std::map<int16, ItemInst*> &collection) { iter_inst it; iter_contents itb; ItemInst* inst = nullptr; for (it=collection.begin(); it!=collection.end(); ++it) { inst = it->second; if(!inst || !inst->GetItem()) continue; std::string slot; StringFormat(slot, "Slot %d: %s (%d)",it->first, it->second->GetItem()->Name, (inst->GetCharges()<=0) ? 1 : inst->GetCharges()); std::cout << slot << std::endl; dumpBagContents(inst, &it); } }
void ItemInst::PutItem(uint8 index, const ItemInst& inst) { // Clean up item already in slot (if exists) DeleteItem(index); // Delegate to internal method _PutItem(index, inst.Clone()); }
void Inventory::dumpBagContents(ItemInst *inst, iter_inst *it) { iter_contents itb; if (!inst || !inst->IsType(ItemClassContainer)) return; // Go through bag, if bag for (itb=inst->_begin(); itb!=inst->_end(); ++itb) { ItemInst* baginst = itb->second; if(!baginst || !baginst->GetItem()) continue; std::string subSlot; StringFormat(subSlot," Slot %d: %s (%d)", Inventory::CalcSlotId((*it)->first, itb->first), baginst->GetItem()->Name, (baginst->GetCharges()<=0) ? 1 : baginst->GetCharges()); std::cout << subSlot << std::endl; } }
// Put an item snto specified slot sint16 Inventory::PutItem(sint16 slot_id, const ItemInst& inst) { // Clean up item already in slot (if exists) DeleteItem(slot_id); if (!inst) { // User is effectively deleting the item // in the slot, why hold a null ptr in map<>? return slot_id; } // Delegate to internal method return _PutItem(slot_id, inst.Clone()); }
void Object::Close() { m_inuse = false; if(user != nullptr) { last_user = user; // put any remaining items from the world container back into the player's inventory to avoid item loss // if they close the container without removing all items ItemInst* container = this->m_inst; if(container != nullptr) { for (uint8 i = SUB_BEGIN; i < EmuConstants::ITEM_CONTAINER_SIZE; i++) { ItemInst* inst = container->PopItem(i); if(inst != nullptr) { user->MoveItemToInventory(inst, true); } } } user->SetTradeskillObject(nullptr); } user = nullptr; }
void Object::Close() { m_inuse = false; if(user != NULL) { last_user = user; // put any remaining items from the world container back into the player's inventory to avoid item loss // if they close the container without removing all items ItemInst* container = this->m_inst; if(container != NULL) { for (uint8 i = 0; i < MAX_ITEMS_PER_BAG; i++) { ItemInst* inst = container->PopItem(i); if(inst != NULL) { user->MoveItemToInventory(inst, true); } } } user->SetTradeskillObject(NULL); } user = NULL; }
// Internal Method: Checks an inventory queue type bucket for a particular item sint16 Inventory::_HasItem(ItemInstQueue& iqueue, uint32 item_id, uint8 quantity) { iter_queue it; iter_contents itb; uint8 quantity_found = 0; // Read-only iteration of queue for (it=iqueue.begin(); it!=iqueue.end(); it++) { ItemInst* inst = *it; if (inst) { if (inst->GetID() == item_id) { quantity_found += (inst->GetCharges()<=0) ? 1 : inst->GetCharges(); if (quantity_found >= quantity) return SLOT_CURSOR; } for(int i = 0; i < MAX_AUGMENT_SLOTS; i++) { if (inst->GetAugmentItemID(i) == item_id && quantity <= 1) return SLOT_AUGMENT; // Only one augment per slot. } } // Go through bag, if bag if (inst && inst->IsType(ItemClassContainer)) { for (itb=inst->_begin(); itb!=inst->_end(); itb++) { ItemInst* baginst = itb->second; if (baginst->GetID() == item_id) { quantity_found += (baginst->GetCharges()<=0) ? 1 : baginst->GetCharges(); if (quantity_found >= quantity) return Inventory::CalcSlotId(SLOT_CURSOR, itb->first); } for(int i = 0; i < MAX_AUGMENT_SLOTS; i++) { if (baginst->GetAugmentItemID(i) == item_id && quantity <= 1) return SLOT_AUGMENT; // Only one augment per slot. } } } } // Not found return SLOT_INVALID; }
void Inventory::dumpInventory() { iter_inst it; iter_contents itb; ItemInst* inst = NULL; // Check item: After failed checks, check bag contents (if bag) printf("Worn items:\n"); for (it=m_worn.begin(); it!=m_worn.end(); it++) { inst = it->second; it->first; if(!inst || !inst->GetItem()) continue; printf("Slot %d: %s (%d)\n", it->first, it->second->GetItem()->Name, (inst->GetCharges()<=0) ? 1 : inst->GetCharges()); // Go through bag, if bag if (inst && inst->IsType(ItemClassContainer)) { for (itb=inst->_begin(); itb!=inst->_end(); itb++) { ItemInst* baginst = itb->second; if(!baginst || !baginst->GetItem()) continue; printf(" Slot %d: %s (%d)\n", Inventory::CalcSlotId(it->first, itb->first), baginst->GetItem()->Name, (baginst->GetCharges()<=0) ? 1 : baginst->GetCharges()); } } } printf("Inventory items:\n"); for (it=m_inv.begin(); it!=m_inv.end(); it++) { inst = it->second; it->first; if(!inst || !inst->GetItem()) continue; printf("Slot %d: %s (%d)\n", it->first, it->second->GetItem()->Name, (inst->GetCharges()<=0) ? 1 : inst->GetCharges()); // Go through bag, if bag if (inst && inst->IsType(ItemClassContainer)) { for (itb=inst->_begin(); itb!=inst->_end(); itb++) { ItemInst* baginst = itb->second; if(!baginst || !baginst->GetItem()) continue; printf(" Slot %d: %s (%d)\n", Inventory::CalcSlotId(it->first, itb->first), baginst->GetItem()->Name, (baginst->GetCharges()<=0) ? 1 : baginst->GetCharges()); } } } printf("Bank items:\n"); for (it=m_bank.begin(); it!=m_bank.end(); it++) { inst = it->second; it->first; if(!inst || !inst->GetItem()) continue; printf("Slot %d: %s (%d)\n", it->first, it->second->GetItem()->Name, (inst->GetCharges()<=0) ? 1 : inst->GetCharges()); // Go through bag, if bag if (inst && inst->IsType(ItemClassContainer)) { for (itb=inst->_begin(); itb!=inst->_end(); itb++) { ItemInst* baginst = itb->second; if(!baginst || !baginst->GetItem()) continue; printf(" Slot %d: %s (%d)\n", Inventory::CalcSlotId(it->first, itb->first), baginst->GetItem()->Name, (baginst->GetCharges()<=0) ? 1 : baginst->GetCharges()); } } } printf("Shared Bank items:\n"); for (it=m_shbank.begin(); it!=m_shbank.end(); it++) { inst = it->second; it->first; if(!inst || !inst->GetItem()) continue; printf("Slot %d: %s (%d)\n", it->first, it->second->GetItem()->Name, (inst->GetCharges()<=0) ? 1 : inst->GetCharges()); // Go through bag, if bag if (inst && inst->IsType(ItemClassContainer)) { for (itb=inst->_begin(); itb!=inst->_end(); itb++) { ItemInst* baginst = itb->second; if(!baginst || !baginst->GetItem()) continue; printf(" Slot %d: %s (%d)\n", Inventory::CalcSlotId(it->first, itb->first), baginst->GetItem()->Name, (baginst->GetCharges()<=0) ? 1 : baginst->GetCharges()); } } } printf("\n"); fflush(stdout); }
uint32 Client::CalcCurrentWeight() { const Item_Struct* TempItem = 0; ItemInst* ins; uint32 Total = 0; int x; for(x = EmuConstants::EQUIPMENT_BEGIN; x <= MainCursor; x++) // include cursor or not? { TempItem = 0; ins = GetInv().GetItem(x); if (ins) TempItem = ins->GetItem(); if (TempItem) Total += TempItem->Weight; } for (x = EmuConstants::GENERAL_BAGS_BEGIN; x <= EmuConstants::GENERAL_BAGS_END; x++) // include cursor bags or not? { int TmpWeight = 0; TempItem = 0; ins = GetInv().GetItem(x); if (ins) TempItem = ins->GetItem(); if (TempItem) TmpWeight = TempItem->Weight; if (TmpWeight > 0) { // this code indicates that weight redux bags can only be in the first general inventory slot to be effective... // is this correct? or can we scan for the highest weight redux and use that? (need client verifications) int bagslot = MainGeneral1; int reduction = 0; for (int m = EmuConstants::GENERAL_BAGS_BEGIN + 10; m <= EmuConstants::GENERAL_BAGS_END; m += 10) // include cursor bags or not? { if (x >= m) bagslot += 1; } ItemInst* baginst = GetInv().GetItem(bagslot); if (baginst && baginst->GetItem() && baginst->IsType(ItemClassContainer)) reduction = baginst->GetItem()->BagWR; if (reduction > 0) TmpWeight -= TmpWeight*reduction/100; Total += TmpWeight; } } //TODO: coin weight reduction (from purses, etc), since client already calculates it /*From the Wiki http://www.eqemulator.net/wiki/wikka.php?wakka=EQEmuDBSchemaitems under bagwr (thanks Trevius): Interestingly, you can also have bags that reduce coin weight. However, in order to set bags to reduce coin weight, you MUST set the Item ID somewhere between 17201 and 17230. This is hard coded into the client. The client is set to have certain coin weight reduction on a per Item ID basis within this range. The best way to create an new item to reduce coin weight is to examine existing bags in this range. Search for the words "coin purse" with the #finditem command in game and the Bag WR setting on those bags is the amount they will reduce coin weight. It is easiest to overwrite one of those bags if you wish to create one with the same weight reduction amount for coins. You can use other Item IDs in this range for setting coin weight reduction, but by using an existing item, at least you will know the amount the client will reduce it by before you create it. This is the ONLY instance I have seen where the client is hard coded to particular Item IDs to set a certain property for an item. It is very odd. */ // SoD+ client has no weight for coin if (EQLimits::CoinHasWeight(ClientVersion)) Total += (m_pp.platinum + m_pp.gold + m_pp.silver + m_pp.copper) / 4; float Packrat = (float)spellbonuses.Packrat + (float)aabonuses.Packrat + (float)itembonuses.Packrat; if (Packrat > 0) Total = (uint32)((float)Total * (1.0f - ((Packrat * 1.0f) / 100.0f))); //AndMetal: 1% per level, up to 5% (calculated from Titanium client). verified thru client that it reduces coin weight by the same % //without casting to float & back to uint32, this didn't work right return Total; }
// Internal Method: Checks an inventory bucket for a particular item sint16 Inventory::_HasItem(map<sint16, ItemInst*>& bucket, uint32 item_id, uint8 quantity) { iter_inst it; iter_contents itb; ItemInst* inst = NULL; uint8 quantity_found = 0; // Check item: After failed checks, check bag contents (if bag) for (it=bucket.begin(); it!=bucket.end(); it++) { inst = it->second; if (inst) { if (inst->GetID() == item_id) { quantity_found += (inst->GetCharges()<=0) ? 1 : inst->GetCharges(); if (quantity_found >= quantity) return it->first; } for(int i = 0; i < MAX_AUGMENT_SLOTS; i++) { if (inst->GetAugmentItemID(i) == item_id && quantity <= 1) return SLOT_AUGMENT; // Only one augment per slot. } } // Go through bag, if bag if (inst && inst->IsType(ItemClassContainer)) { for (itb=inst->_begin(); itb!=inst->_end(); itb++) { ItemInst* baginst = itb->second; if (baginst->GetID() == item_id) { quantity_found += (baginst->GetCharges()<=0) ? 1 : baginst->GetCharges(); if (quantity_found >= quantity) return Inventory::CalcSlotId(it->first, itb->first); } for(int i = 0; i < MAX_AUGMENT_SLOTS; i++) { if (baginst->GetAugmentItemID(i) == item_id && quantity <= 1) return SLOT_AUGMENT; // Only one augment per slot. } } } } // Not found return SLOT_INVALID; }
bool Inventory::HasSpaceForItem(const Item_Struct *ItemToTry, sint16 Quantity) { if(ItemToTry->Stackable) { for(sint16 i = 22; i <= 29; i++) { ItemInst* InvItem = GetItem(i); if(InvItem && (InvItem->GetItem()->ID == ItemToTry->ID) && (InvItem->GetCharges() < InvItem->GetItem()->StackSize)) { int ChargeSlotsLeft = InvItem->GetItem()->StackSize - InvItem->GetCharges(); if(Quantity <= ChargeSlotsLeft) return true; Quantity -= ChargeSlotsLeft; } if (InvItem && InvItem->IsType(ItemClassContainer)) { sint16 BaseSlotID = Inventory::CalcSlotId(i, 0); int8 BagSize=InvItem->GetItem()->BagSlots; for (uint8 BagSlot = 0; BagSlot < BagSize; BagSlot++) { InvItem = GetItem(BaseSlotID + BagSlot); if(InvItem && (InvItem->GetItem()->ID == ItemToTry->ID) && (InvItem->GetCharges() < InvItem->GetItem()->StackSize)) { int ChargeSlotsLeft = InvItem->GetItem()->StackSize - InvItem->GetCharges(); if(Quantity <= ChargeSlotsLeft) return true; Quantity -= ChargeSlotsLeft; } } } } } for (sint16 i = 22; i <= 29; i++) { ItemInst* InvItem = GetItem(i); if (!InvItem) { if(!ItemToTry->Stackable) { if(Quantity == 1) return true; else Quantity--; } else { if(Quantity <= ItemToTry->StackSize) return true; else Quantity -= ItemToTry->StackSize; } } else if(InvItem->IsType(ItemClassContainer) && CanItemFitInContainer(ItemToTry, InvItem->GetItem())) { sint16 BaseSlotID = Inventory::CalcSlotId(i, 0); int8 BagSize=InvItem->GetItem()->BagSlots; for (uint8 BagSlot=0; BagSlot<BagSize; BagSlot++) { InvItem = GetItem(BaseSlotID + BagSlot); if(!InvItem) { if(!ItemToTry->Stackable) { if(Quantity == 1) return true; else Quantity--; } else { if(Quantity <= ItemToTry->StackSize) return true; else Quantity -= ItemToTry->StackSize; } } } } } return false; }
sint16 Inventory::PushCursor(const ItemInst& inst) { m_cursor.push(inst.Clone()); return SLOT_CURSOR; }
// Retrieve item at specified slot; returns false if item not found ItemInst* Inventory::GetItem(sint16 slot_id) const { _CP(Inventory_GetItem); ItemInst* result = NULL; // Cursor if (slot_id == SLOT_CURSOR) { // Cursor slot result = m_cursor.peek_front(); } // Non bag slots else if (slot_id>=3000 && slot_id<=3007) { // Trade slots result = _GetItem(m_trade, slot_id); } else if (slot_id>=2500 && slot_id<=2501) { // Shared Bank slots result = _GetItem(m_shbank, slot_id); } else if (slot_id>=2000 && slot_id<=2023) { // Bank slots result = _GetItem(m_bank, slot_id); } else if ((slot_id>=22 && slot_id<=29)) { // Personal inventory slots result = _GetItem(m_inv, slot_id); } else if ((slot_id>=0 && slot_id<=21) || (slot_id >= 400 && slot_id<=404) || (slot_id == 9999)) { // Equippable slots (on body) result = _GetItem(m_worn, slot_id); } // Inner bag slots else if (slot_id>=3031 && slot_id<=3110) { // Trade bag slots ItemInst* inst = _GetItem(m_trade, Inventory::CalcSlotId(slot_id)); if (inst && inst->IsType(ItemClassContainer)) { result = inst->GetItem(Inventory::CalcBagIdx(slot_id)); } } else if (slot_id>=2531 && slot_id<=2550) { // Shared Bank bag slots ItemInst* inst = _GetItem(m_shbank, Inventory::CalcSlotId(slot_id)); if (inst && inst->IsType(ItemClassContainer)) { result = inst->GetItem(Inventory::CalcBagIdx(slot_id)); } } else if (slot_id>=2031 && slot_id<=2270) { // Bank bag slots ItemInst* inst = _GetItem(m_bank, Inventory::CalcSlotId(slot_id)); if (inst && inst->IsType(ItemClassContainer)) { result = inst->GetItem(Inventory::CalcBagIdx(slot_id)); } } else if (slot_id>=331 && slot_id<=340) { // Cursor bag slots ItemInst* inst = m_cursor.peek_front(); if (inst && inst->IsType(ItemClassContainer)) { result = inst->GetItem(Inventory::CalcBagIdx(slot_id)); } } else if (slot_id>=251 && slot_id<=330) { // Personal inventory bag slots ItemInst* inst = _GetItem(m_inv, Inventory::CalcSlotId(slot_id)); if (inst && inst->IsType(ItemClassContainer)) { result = inst->GetItem(Inventory::CalcBagIdx(slot_id)); } } return result; }
Corpse::Corpse(Client* client, int32 in_rezexp) : Mob ( "Unnamed_Corpse", // const char* in_name, "", // const char* in_lastname, 0, // int32 in_cur_hp, 0, // int32 in_max_hp, client->GetGender(), // uint8 in_gender, client->GetRace(), // uint16 in_race, client->GetClass(), // uint8 in_class, BT_Humanoid, // bodyType in_bodytype, client->GetDeity(), // uint8 in_deity, client->GetLevel(), // uint8 in_level, 0, // uint32 in_npctype_id, client->GetSize(), // float in_size, 0, // float in_runspeed, client->GetPosition(), client->GetInnateLightType(), // uint8 in_light, - verified for client innate_light value client->GetTexture(), // uint8 in_texture, client->GetHelmTexture(), // uint8 in_helmtexture, 0, // uint16 in_ac, 0, // uint16 in_atk, 0, // uint16 in_str, 0, // uint16 in_sta, 0, // uint16 in_dex, 0, // uint16 in_agi, 0, // uint16 in_int, 0, // uint16 in_wis, 0, // uint16 in_cha, client->GetPP().haircolor, // uint8 in_haircolor, client->GetPP().beardcolor, // uint8 in_beardcolor, client->GetPP().eyecolor1, // uint8 in_eyecolor1, // the eyecolors always seem to be the same, maybe left and right eye? client->GetPP().eyecolor2, // uint8 in_eyecolor2, client->GetPP().hairstyle, // uint8 in_hairstyle, client->GetPP().face, // uint8 in_luclinface, client->GetPP().beard, // uint8 in_beard, client->GetPP().drakkin_heritage, // uint32 in_drakkin_heritage, client->GetPP().drakkin_tattoo, // uint32 in_drakkin_tattoo, client->GetPP().drakkin_details, // uint32 in_drakkin_details, 0, // uint32 in_armor_tint[_MaterialCount], 0xff, // uint8 in_aa_title, 0, // uint8 in_see_invis, // see through invis 0, // uint8 in_see_invis_undead, // see through invis vs. undead 0, // uint8 in_see_hide, 0, // uint8 in_see_improved_hide, 0, // int32 in_hp_regen, 0, // int32 in_mana_regen, 0, // uint8 in_qglobal, 0, // uint8 in_maxlevel, 0, // uint32 in_scalerate 0, // uint8 in_armtexture, 0, // uint8 in_bracertexture, 0, // uint8 in_handtexture, 0, // uint8 in_legtexture, 0 // uint8 in_feettexture, ), corpse_decay_timer(RuleI(Character, CorpseDecayTimeMS)), corpse_rez_timer(RuleI(Character, CorpseResTimeMS)), corpse_delay_timer(RuleI(NPC, CorpseUnlockTimer)), corpse_graveyard_timer(RuleI(Zone, GraveyardTimeMS)), loot_cooldown_timer(10) { int i; PlayerProfile_Struct *pp = &client->GetPP(); ItemInst *item; /* Check if Zone has Graveyard First */ if(!zone->HasGraveyard()) { corpse_graveyard_timer.Disable(); } memset(item_tint, 0, sizeof(item_tint)); for (i = 0; i < MAX_LOOTERS; i++){ allowed_looters[i] = 0; } is_corpse_changed = true; rez_experience = in_rezexp; can_corpse_be_rezzed = true; is_player_corpse = true; is_locked = false; being_looted_by = 0xFFFFFFFF; char_id = client->CharacterID(); corpse_db_id = 0; player_corpse_depop = false; copper = 0; silver = 0; gold = 0; platinum = 0; strcpy(corpse_name, pp->name); strcpy(name, pp->name); /* become_npc was not being initialized which led to some pretty funky things with newly created corpses */ become_npc = false; SetPlayerKillItemID(0); /* Check Rule to see if we can leave corpses */ if(!RuleB(Character, LeaveNakedCorpses) || RuleB(Character, LeaveCorpses) && GetLevel() >= RuleI(Character, DeathItemLossLevel)) { // cash // Let's not move the cash when 'RespawnFromHover = true' && 'client->GetClientVersion() < EQClientSoF' since the client doesn't. // (change to first client that supports 'death hover' mode, if not SoF.) if (!RuleB(Character, RespawnFromHover) || client->GetClientVersion() < ClientVersion::SoF) { SetCash(pp->copper, pp->silver, pp->gold, pp->platinum); pp->copper = 0; pp->silver = 0; pp->gold = 0; pp->platinum = 0; } // get their tints memcpy(item_tint, &client->GetPP().item_tint, sizeof(item_tint)); // TODO soulbound items need not be added to corpse, but they need // to go into the regular slots on the player, out of bags std::list<uint32> removed_list; for(i = MAIN_BEGIN; i < EmuConstants::MAP_POSSESSIONS_SIZE; ++i) { if(i == MainAmmo && client->GetClientVersion() >= ClientVersion::SoF) { item = client->GetInv().GetItem(MainPowerSource); if (item != nullptr) { if (!client->IsBecomeNPC() || (client->IsBecomeNPC() && !item->GetItem()->NoRent)) MoveItemToCorpse(client, item, MainPowerSource, removed_list); } } item = client->GetInv().GetItem(i); if (item == nullptr) { continue; } if(!client->IsBecomeNPC() || (client->IsBecomeNPC() && !item->GetItem()->NoRent)) MoveItemToCorpse(client, item, i, removed_list); } database.TransactionBegin(); // I have an untested process that avoids this snarl up when all possessions inventory is removed..but this isn't broke if (!removed_list.empty()) { std::stringstream ss(""); ss << "DELETE FROM inventory WHERE charid=" << client->CharacterID(); ss << " AND ("; std::list<uint32>::const_iterator iter = removed_list.begin(); bool first = true; while (iter != removed_list.end()) { if (first) { first = false; } else { ss << " OR "; } ss << "slotid=" << (*iter); ++iter; } ss << ")"; database.QueryDatabase(ss.str().c_str()); } auto start = client->GetInv().cursor_cbegin(); auto finish = client->GetInv().cursor_cend(); database.SaveCursor(client->CharacterID(), start, finish); client->CalcBonuses(); client->Save(); IsRezzed(false); Save(); database.TransactionCommit(); UpdateEquipmentLight(); UpdateActiveLight(); return; } //end "not leaving naked corpses" UpdateEquipmentLight(); UpdateActiveLight(); IsRezzed(false); Save(); }
// Internal Method: Checks an inventory queue type bucket for a particular item sint16 Inventory::_HasItemByLoreGroup(ItemInstQueue& iqueue, uint32 loregroup) { iter_queue it; iter_contents itb; // Read-only iteration of queue for (it=iqueue.begin(); it!=iqueue.end(); it++) { ItemInst* inst = *it; if (inst) { if (inst->GetItem()->LoreGroup == loregroup) return SLOT_CURSOR; ItemInst* Aug; for(int i = 0; i < MAX_AUGMENT_SLOTS; i++) { Aug = inst->GetAugment(i); if (Aug && Aug->GetItem()->LoreGroup == loregroup) return SLOT_AUGMENT; // Only one augment per slot. } } // Go through bag, if bag if (inst && inst->IsType(ItemClassContainer)) { for (itb=inst->_begin(); itb!=inst->_end(); itb++) { ItemInst* baginst = itb->second; if (baginst && baginst->IsType(ItemClassCommon)&& baginst->GetItem()->LoreGroup == loregroup) return Inventory::CalcSlotId(SLOT_CURSOR, itb->first); ItemInst* Aug2; for(int i = 0; i < MAX_AUGMENT_SLOTS; i++) { Aug2 = baginst->GetAugment(i); if (Aug2 && Aug2->GetItem()->LoreGroup == loregroup) return SLOT_AUGMENT; // Only one augment per slot. } } } } // Not found return SLOT_INVALID; }
sint16 Inventory::_HasItemByLoreGroup(map<sint16, ItemInst*>& bucket, uint32 loregroup) { iter_inst it; iter_contents itb; ItemInst* inst = NULL; // Check item: After failed checks, check bag contents (if bag) for (it=bucket.begin(); it!=bucket.end(); it++) { inst = it->second; if (inst) { if (inst->GetItem()->LoreGroup == loregroup) return it->first; ItemInst* Aug; for(int i = 0; i < MAX_AUGMENT_SLOTS; i++) { Aug = inst->GetAugment(i); if (Aug && Aug->GetItem()->LoreGroup == loregroup) return SLOT_AUGMENT; // Only one augment per slot. } } // Go through bag, if bag if (inst && inst->IsType(ItemClassContainer)) { for (itb=inst->_begin(); itb!=inst->_end(); itb++) { ItemInst* baginst = itb->second; if (baginst && baginst->IsType(ItemClassCommon)&& baginst->GetItem()->LoreGroup == loregroup) return Inventory::CalcSlotId(it->first, itb->first); ItemInst* Aug2; for(int i = 0; i < MAX_AUGMENT_SLOTS; i++) { Aug2 = baginst->GetAugment(i); if (Aug2 && Aug2->GetItem()->LoreGroup == loregroup) return SLOT_AUGMENT; // Only one augment per slot. } } } } // Not found return SLOT_INVALID; }
void Corpse::LootItem(Client* client, const EQApplicationPacket* app) { /* This gets sent no matter what as a sort of ACK */ client->QueuePacket(app); if (!loot_cooldown_timer.Check()) { SendEndLootErrorPacket(client); //unlock corpse for others if (this->being_looted_by = client->GetID()) { being_looted_by = 0xFFFFFFFF; } return; } /* To prevent item loss for a player using 'Loot All' who doesn't have inventory space for all their items. */ if (RuleB(Character, CheckCursorEmptyWhenLooting) && !client->GetInv().CursorEmpty()) { client->Message(13, "You may not loot an item while you have an item on your cursor."); SendEndLootErrorPacket(client); /* Unlock corpse for others */ if (this->being_looted_by = client->GetID()) { being_looted_by = 0xFFFFFFFF; } return; } LootingItem_Struct* lootitem = (LootingItem_Struct*)app->pBuffer; if (this->being_looted_by != client->GetID()) { client->Message(13, "Error: Corpse::LootItem: BeingLootedBy != client"); SendEndLootErrorPacket(client); return; } if (IsPlayerCorpse() && !CanPlayerLoot(client->CharacterID()) && !become_npc && (char_id != client->CharacterID() && client->Admin() < 150)) { client->Message(13, "Error: This is a player corpse and you dont own it."); SendEndLootErrorPacket(client); return; } if (is_locked && client->Admin() < 100) { SendLootReqErrorPacket(client, 0); client->Message(13, "Error: Corpse locked by GM."); return; } if (IsPlayerCorpse() && (char_id != client->CharacterID()) && CanPlayerLoot(client->CharacterID()) && GetPlayerKillItem() == 0){ client->Message(13, "Error: You cannot loot any more items from this corpse."); SendEndLootErrorPacket(client); being_looted_by = 0xFFFFFFFF; return; } const Item_Struct* item = 0; ItemInst *inst = 0; ServerLootItem_Struct* item_data = nullptr, *bag_item_data[10]; memset(bag_item_data, 0, sizeof(bag_item_data)); if (GetPlayerKillItem() > 1){ item = database.GetItem(GetPlayerKillItem()); } else if (GetPlayerKillItem() == -1 || GetPlayerKillItem() == 1){ item_data = GetItem(lootitem->slot_id - EmuConstants::CORPSE_BEGIN); //dont allow them to loot entire bags of items as pvp reward } else{ item_data = GetItem(lootitem->slot_id - EmuConstants::CORPSE_BEGIN, bag_item_data); } if (GetPlayerKillItem()<=1 && item_data != 0) { item = database.GetItem(item_data->item_id); } if (item != 0) { if (item_data){ inst = database.CreateItem(item, item_data ? item_data->charges : 0, item_data->aug_1, item_data->aug_2, item_data->aug_3, item_data->aug_4, item_data->aug_5, item_data->aug_6, item_data->attuned); } else { inst = database.CreateItem(item); } } if (client && inst) { if (client->CheckLoreConflict(item)) { client->Message_StringID(0, LOOT_LORE_ERROR); SendEndLootErrorPacket(client); being_looted_by = 0; delete inst; return; } if (inst->IsAugmented()) { for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) { ItemInst *itm = inst->GetAugment(i); if (itm) { if (client->CheckLoreConflict(itm->GetItem())) { client->Message_StringID(0, LOOT_LORE_ERROR); SendEndLootErrorPacket(client); being_looted_by = 0; delete inst; return; } } } } char buf[88]; char corpse_name[64]; strcpy(corpse_name, corpse_name); snprintf(buf, 87, "%d %d %s", inst->GetItem()->ID, inst->GetCharges(), EntityList::RemoveNumbers(corpse_name)); buf[87] = '\0'; std::vector<EQEmu::Any> args; args.push_back(inst); args.push_back(this); parse->EventPlayer(EVENT_LOOT, client, buf, 0, &args); parse->EventItem(EVENT_LOOT, client, inst, this, buf, 0); if (!IsPlayerCorpse() && RuleB(Character, EnableDiscoveredItems)) { if (client && !client->GetGM() && !client->IsDiscovered(inst->GetItem()->ID)) client->DiscoverItem(inst->GetItem()->ID); } if (zone->adv_data) { ServerZoneAdventureDataReply_Struct *ad = (ServerZoneAdventureDataReply_Struct*)zone->adv_data; if (ad->type == Adventure_Collect && !IsPlayerCorpse()) { if (ad->data_id == inst->GetItem()->ID) { zone->DoAdventureCountIncrease(); } } } /* First add it to the looter - this will do the bag contents too */ if (lootitem->auto_loot) { if (!client->AutoPutLootInInventory(*inst, true, true, bag_item_data)) client->PutLootInInventory(MainCursor, *inst, bag_item_data); } else { client->PutLootInInventory(MainCursor, *inst, bag_item_data); } /* Update any tasks that have an activity to loot this item */ if (RuleB(TaskSystem, EnableTaskSystem)) client->UpdateTasksForItem(ActivityLoot, item->ID); /* Remove it from Corpse */ if (item_data){ /* Delete needs to be before RemoveItem because its deletes the pointer for item_data/bag_item_data */ database.DeleteItemOffCharacterCorpse(this->corpse_db_id, item_data->equip_slot, item_data->item_id); /* Delete Item Instance */ RemoveItem(item_data->lootslot); } /* Remove Bag Contents */ if (item->ItemClass == ItemClassContainer && (GetPlayerKillItem() != -1 || GetPlayerKillItem() != 1)) { for (int i = SUB_BEGIN; i < EmuConstants::ITEM_CONTAINER_SIZE; i++) { if (bag_item_data[i]) { /* Delete needs to be before RemoveItem because its deletes the pointer for item_data/bag_item_data */ database.DeleteItemOffCharacterCorpse(this->corpse_db_id, bag_item_data[i]->equip_slot, bag_item_data[i]->item_id); /* Delete Item Instance */ RemoveItem(bag_item_data[i]); } } } if (GetPlayerKillItem() != -1) { SetPlayerKillItemID(0); } /* Send message with item link to groups and such */ Client::TextLink linker; linker.SetLinkType(linker.linkItemInst); linker.SetItemInst(inst); auto item_link = linker.GenerateLink(); client->Message_StringID(MT_LootMessages, LOOTED_MESSAGE, item_link.c_str()); if (!IsPlayerCorpse()) { Group *g = client->GetGroup(); if(g != nullptr) { g->GroupMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE, client->GetName(), item_link.c_str()); } else { Raid *r = client->GetRaid(); if(r != nullptr) { r->RaidMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE, client->GetName(), item_link.c_str()); } } } } else { SendEndLootErrorPacket(client); safe_delete(inst); return; } if (IsPlayerCorpse()){ client->SendItemLink(inst); } else{ client->SendItemLink(inst, true); } safe_delete(inst); }
// Internal Method: Checks an inventory bucket for a particular item sint16 Inventory::_HasItemByUse(map<sint16, ItemInst*>& bucket, uint8 use, uint8 quantity) { iter_inst it; iter_contents itb; ItemInst* inst = NULL; uint8 quantity_found = 0; // Check item: After failed checks, check bag contents (if bag) for (it=bucket.begin(); it!=bucket.end(); it++) { inst = it->second; if (inst && inst->IsType(ItemClassCommon) && inst->GetItem()->ItemType == use) { quantity_found += (inst->GetCharges()<=0) ? 1 : inst->GetCharges(); if (quantity_found >= quantity) return it->first; } // Go through bag, if bag if (inst && inst->IsType(ItemClassContainer)) { for (itb=inst->_begin(); itb!=inst->_end(); itb++) { ItemInst* baginst = itb->second; if (baginst && baginst->IsType(ItemClassCommon) && baginst->GetItem()->ItemType == use) { quantity_found += (baginst->GetCharges()<=0) ? 1 : baginst->GetCharges(); if (quantity_found >= quantity) return Inventory::CalcSlotId(it->first, itb->first); } } } } // Not found return SLOT_INVALID; }
void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* app) { // Added 12/08. Started compressing loot struct on live. char tmp[10]; if(player_corpse_depop) { SendLootReqErrorPacket(client, 0); return; } if(IsPlayerCorpse() && corpse_db_id == 0) { // SendLootReqErrorPacket(client, 0); client->Message(13, "Warning: Corpse's dbid = 0! Corpse will not survive zone shutdown!"); std::cout << "Error: PlayerCorpse::MakeLootRequestPackets: dbid = 0!" << std::endl; // return; } if(is_locked && client->Admin() < 100) { SendLootReqErrorPacket(client, 0); client->Message(13, "Error: Corpse locked by GM."); return; } if(being_looted_by == 0) being_looted_by = 0xFFFFFFFF; if(this->being_looted_by != 0xFFFFFFFF) { // lets double check.... Entity* looter = entity_list.GetID(this->being_looted_by); if(looter == 0) this->being_looted_by = 0xFFFFFFFF; } uint8 Loot_Request_Type = 1; bool loot_coin = false; if(database.GetVariable("LootCoin", tmp, 9)) loot_coin = (atoi(tmp) == 1); if (this->being_looted_by != 0xFFFFFFFF && this->being_looted_by != client->GetID()) { SendLootReqErrorPacket(client, 0); Loot_Request_Type = 0; } else if (IsPlayerCorpse() && char_id == client->CharacterID()) { Loot_Request_Type = 2; } else if ((IsNPCCorpse() || become_npc) && CanPlayerLoot(client->CharacterID())) { Loot_Request_Type = 2; } else if (GetPlayerKillItem() == -1 && CanPlayerLoot(client->CharacterID())) { /* PVP loot all items, variable cash */ Loot_Request_Type = 3; } else if (GetPlayerKillItem() == 1 && CanPlayerLoot(client->CharacterID())) { /* PVP loot 1 item, variable cash */ Loot_Request_Type = 4; } else if (GetPlayerKillItem() > 1 && CanPlayerLoot(client->CharacterID())) { /* PVP loot 1 set item, variable cash */ Loot_Request_Type = 5; } if (Loot_Request_Type == 1) { if (client->Admin() < 100 || !client->GetGM()) { SendLootReqErrorPacket(client, 2); } } if(Loot_Request_Type >= 2 || (Loot_Request_Type == 1 && client->Admin() >= 100 && client->GetGM())) { this->being_looted_by = client->GetID(); EQApplicationPacket* outapp = new EQApplicationPacket(OP_MoneyOnCorpse, sizeof(moneyOnCorpseStruct)); moneyOnCorpseStruct* d = (moneyOnCorpseStruct*) outapp->pBuffer; d->response = 1; d->unknown1 = 0x42; d->unknown2 = 0xef; /* Dont take the coin off if it's a gm peeking at the corpse */ if(Loot_Request_Type == 2 || (Loot_Request_Type >= 3 && loot_coin)) { if(!IsPlayerCorpse() && client->IsGrouped() && client->AutoSplitEnabled() && client->GetGroup()) { d->copper = 0; d->silver = 0; d->gold = 0; d->platinum = 0; Group *cgroup = client->GetGroup(); cgroup->SplitMoney(GetCopper(), GetSilver(), GetGold(), GetPlatinum(), client); } else { d->copper = this->GetCopper(); d->silver = this->GetSilver(); d->gold = this->GetGold(); d->platinum = this->GetPlatinum(); client->AddMoneyToPP(GetCopper(), GetSilver(), GetGold(), GetPlatinum(), false); } RemoveCash(); Save(); } auto timestamps = database.GetItemRecastTimestamps(client->CharacterID()); outapp->priority = 6; client->QueuePacket(outapp); safe_delete(outapp); if(Loot_Request_Type == 5) { int pkitem = GetPlayerKillItem(); const Item_Struct* item = database.GetItem(pkitem); ItemInst* inst = database.CreateItem(item, item->MaxCharges); if(inst) { if (item->RecastDelay) inst->SetRecastTimestamp(timestamps.count(item->RecastType) ? timestamps.at(item->RecastType) : 0); client->SendItemPacket(EmuConstants::CORPSE_BEGIN, inst, ItemPacketLoot); safe_delete(inst); } else { client->Message(13, "Could not find item number %i to send!!", GetPlayerKillItem()); } client->QueuePacket(app); return; } int i = 0; const Item_Struct* item = 0; ItemList::iterator cur,end; cur = itemlist.begin(); end = itemlist.end(); int corpselootlimit = EQLimits::InventoryMapSize(MapCorpse, client->GetClientVersion()); for(; cur != end; ++cur) { ServerLootItem_Struct* item_data = *cur; item_data->lootslot = 0xFFFF; // Dont display the item if it's in a bag // Added cursor queue slots to corpse item visibility list. Nothing else should be making it to corpse. if(!IsPlayerCorpse() || item_data->equip_slot <= MainCursor || item_data->equip_slot == MainPowerSource || Loot_Request_Type>=3 || (item_data->equip_slot >= 8000 && item_data->equip_slot <= 8999)) { if(i < corpselootlimit) { item = database.GetItem(item_data->item_id); if(client && item) { ItemInst* inst = database.CreateItem(item, item_data->charges, item_data->aug_1, item_data->aug_2, item_data->aug_3, item_data->aug_4, item_data->aug_5, item_data->aug_6, item_data->attuned); if(inst) { if (item->RecastDelay) inst->SetRecastTimestamp(timestamps.count(item->RecastType) ? timestamps.at(item->RecastType) : 0); // MainGeneral1 is the corpse inventory start offset for Ti(EMu) - CORPSE_END = MainGeneral1 + MainCursor client->SendItemPacket(i + EmuConstants::CORPSE_BEGIN, inst, ItemPacketLoot); safe_delete(inst); } item_data->lootslot = i; } } i++; } } if(IsPlayerCorpse() && (char_id == client->CharacterID() || client->GetGM())) { if(i > corpselootlimit) { client->Message(15, "*** This corpse contains more items than can be displayed! ***"); client->Message(0, "Remove items and re-loot corpse to access remaining inventory."); client->Message(0, "(%s contains %i additional %s.)", GetName(), (i - corpselootlimit), (i - corpselootlimit) == 1 ? "item" : "items"); } if(IsPlayerCorpse() && i == 0 && itemlist.size() > 0) { // somehow, player corpse contains items, but client doesn't see them... client->Message(13, "This corpse contains items that are inaccessable!"); client->Message(15, "Contact a GM for item replacement, if necessary."); client->Message(15, "BUGGED CORPSE [DBID: %i, Name: %s, Item Count: %i]", GetCorpseDBID(), GetName(), itemlist.size()); cur = itemlist.begin(); end = itemlist.end(); for(; cur != end; ++cur) { ServerLootItem_Struct* item_data = *cur; item = database.GetItem(item_data->item_id); Log.Out(Logs::General, Logs::None, "Corpse Looting: %s was not sent to client loot window (corpse_dbid: %i, charname: %s(%s))", item->Name, GetCorpseDBID(), client->GetName(), client->GetGM() ? "GM" : "Owner"); client->Message(0, "Inaccessable Corpse Item: %s", item->Name); } } } } // Disgrace: Client seems to require that we send the packet back... client->QueuePacket(app); // This is required for the 'Loot All' feature to work for SoD clients. I expect it is to tell the client that the // server has now sent all the items on the corpse. if(client->GetClientVersion() >= ClientVersion::SoD) { SendLootReqErrorPacket(client, 6); } }
// Internal Method: Checks an inventory queue type bucket for a particular item sint16 Inventory::_HasItemByUse(ItemInstQueue& iqueue, uint8 use, uint8 quantity) { iter_queue it; iter_contents itb; uint8 quantity_found = 0; // Read-only iteration of queue for (it=iqueue.begin(); it!=iqueue.end(); it++) { ItemInst* inst = *it; if (inst && inst->IsType(ItemClassCommon) && inst->GetItem()->ItemType == use) { quantity_found += (inst->GetCharges()<=0) ? 1 : inst->GetCharges(); if (quantity_found >= quantity) return SLOT_CURSOR; } // Go through bag, if bag if (inst && inst->IsType(ItemClassContainer)) { for (itb=inst->_begin(); itb!=inst->_end(); itb++) { ItemInst* baginst = itb->second; if (baginst && baginst->IsType(ItemClassCommon) && baginst->GetItem()->ItemType == use) { quantity_found += (baginst->GetCharges()<=0) ? 1 : baginst->GetCharges(); if (quantity_found >= quantity) return Inventory::CalcSlotId(SLOT_CURSOR, itb->first); } } } } // Not found return SLOT_INVALID; }