//----[ eraseItems ]--------------------------------------------------------- int ClientItemsInterface::eraseItems(unsigned int item_type, int quantity) { for (unsigned int i = 0; (quantity > 0) && (i < items_in_inventory_);) { ItemInstance* item = inventory_[i].item.dereference(); if (!item) { repackInventory(); break; } else { if (item->getDescription()->type_index == item_type) { quantity = item->removeQuantity(quantity); update_inventory_ = true; equipment_changed_ = equipment_changed_ || inventory_[i].equipped; inventory_dirty_bits_.set(i); // check to see if this item was destroyed by removing // the given quantity. if (quantity >= 0) { GlobalDatabaseManager::singleton() ->itemOnAvatarErased(item->getUniqueID()); GlobalItemManager::singleton()->releaseItem(&inventory_[i].item); shiftDownToEraseInInventory(i); } // If the quantity has been consumed, we're done! if (quantity <= 0) return 0; } else { ++i; } } } return quantity; }
//----[ onDeath ]------------------------------------------------------------ bool ClientItemsInterface::onDeath(Magic::MagicIndex* on_death_magic, int* wishing_percent) { assert(on_death_magic); assert(wishing_percent); bool found_on_death_magic = false; int wishing_percent_sum = 0; // iterate backward because we might remove an element for (int i = items_in_inventory_; i > 0;) { --i; if (!inventory_[i].equipped) continue; ItemInstance* item = inventory_[i].item.dereference(); assert(item); Magic::MagicIndex death_magic = item->getDescription()->on_death_magic; wishing_percent_sum += item->getDescription()->wishing_percent; if (!found_on_death_magic && (death_magic != Magic::INVALID_MAGIC_INDEX)) { found_on_death_magic = true; *on_death_magic = death_magic; update_inventory_ = true; GlobalDatabaseManager::singleton() ->itemOnAvatarErased(item->getUniqueID()); GlobalItemManager::singleton() ->releaseItem(&inventory_[i].item); shiftDownToEraseInInventory(i); } } *wishing_percent = wishing_percent_sum; return found_on_death_magic; }
Void Inventory::SortBufferBagItems() { if ( m_arrBags[INVENTORYBAGID_BUFFER].iFreeSlots == INVENTORY_BAG_SIZE ) return; for( UInt i = 0; i < INVENTORY_BAG_SIZE; ++i ) { ItemInstance * pItemInstance = m_arrBags[INVENTORYBAGID_BUFFER].arrSlots[i]; if ( pItemInstance == NULL ) continue; InventoryBagID idTargetBag = INVENTORYBAGID_COUNT; switch( pItemInstance->GetType() ) { case ITEMTYPE_BLOCK: idTargetBag = INVENTORYBAGID_BLOCK; break; case ITEMTYPE_EQUIPMENT: idTargetBag = INVENTORYBAGID_EQUIPMENT; break; case ITEMTYPE_CONSUMABLE: idTargetBag = INVENTORYBAGID_CONSUMABLE; break; case ITEMTYPE_QUEST: idTargetBag = INVENTORYBAGID_QUEST; break; default: Assert(false); break; } if ( m_arrBags[idTargetBag].iFreeSlots == 0 ) continue; UInt iFreeSlot = _Bag_GetFreeSlot( idTargetBag ); Assert( m_arrBags[idTargetBag].arrSlots[iFreeSlot] == NULL ); m_arrBags[INVENTORYBAGID_BUFFER].arrSlots[i] = NULL; m_arrBags[idTargetBag].arrSlots[iFreeSlot] = pItemInstance; ++(m_arrBags[INVENTORYBAGID_BUFFER].iFreeSlots); --(m_arrBags[idTargetBag].iFreeSlots); } SortBag( INVENTORYBAGID_BUFFER ); }
//----[ findStackableItemInInventory ]--------------------------------------- bool ClientItemsInterface::findStackableItemInInventory( ItemInstance* find_match_for, unsigned int start_search_index, unsigned int* found_index, ItemInstance** current_item) { if (!find_match_for) return false; // no item? const Evidyon::Item::ItemServerDescription* description = find_match_for->getDescription(); if (description->max_stack_size <= 1) return false; // not stackable? unsigned int i = start_search_index; while (i < items_in_inventory_) { ItemInstance* item = inventory_[i].item.dereference(); if (!item) { // This item is invalid, but is listed as valid--fix the problem, // then try again. This will loop until no problems are found // or the list is emptied because all are bugged. repackInventory(); } else { if (item->getDescription() == description && !inventory_[i].equipped) { // don't stack equipped items *found_index = start_search_index; *current_item = item; return true; } else { ++i; } } } return false; }
//----[ splitItem ]---------------------------------------------------------- bool ClientItemsInterface::splitItem(unsigned int index) { if (!inventoryItemIsValid(index)) return false; AvatarInventoryItem* inventory_item = &inventory_[index]; if (!inventory_item->stackable || // item must be stackable... inventory_item->equipped) return false; // ...and in the inventory ItemInstance* item = inventory_item->item.dereferenceAssumingValid(); // justified by validity check if (canHoldItems(1) == false) return false; // const int original_quantity = item->getQuantity(); if (original_quantity <= 1) return false; // can't split a stack of 1 int new_quantity = original_quantity >> 1; // divide in half int quantity_remaining = original_quantity - new_quantity; // Create the new item ItemPointer new_item; if (!GlobalItemManager::singleton()->acquireNewItem(new_quantity, item->getDescription()->type_index, &new_item)) { return false; } // Put the new item in the inventory if (!addToInventory(new_item, NULL)) { GlobalItemManager::singleton()->releaseItem(&new_item); } // Adjust the quantity of the original item item->setQuantity(quantity_remaining); return true; }
uint32 EQEmu::ItemInstance::GetItemID(uint8 slot) const { ItemInstance *item = GetItem(slot); if (item) return item->GetID(); return 0; }
//----[ setStorageItem ]----------------------------------------------------- void ClientItemsInterface::setStorageItem(unsigned int index, ItemPointer* item_pointer) { ItemInstance* item = item_pointer->dereferenceAssumingValid(); storage_[index].id = item->getUniqueID(); storage_[index].quantity = item->getQuantity(); storage_[index].type = item->getDescription()->type_index; GlobalItemManager::singleton()->releaseItem(item_pointer); storage_dirty_bits_.set(index); update_storage_ = true; }
//----[ geosidSacrificeItem ]------------------------------------------------ bool ClientItemsInterface::geosidSacrificeItem(unsigned int index, Geosid::Geonite* geonite_value) { if (!inventoryItemIsValid(index)) return false; AvatarInventoryItem* inventory_item = &inventory_[index]; if (inventory_item->equipped) return false; // can't sacrifice equipped items ItemInstance* item = inventory_item->item.dereferenceAssumingValid(); *geonite_value = item->getDescription()->geonite_value; GlobalItemManager::singleton()->releaseItem(&inventory_item->item); shiftDownToEraseInInventory(index); return true; }
bool BarrelBlock::use(Player& player, const BlockPos& pos) { BarrelEntity* container = (BarrelEntity*)player.region.getBlockEntity(pos); if(container == nullptr) return false; Inventory* playerInventory = *(Inventory**) (((uintptr_t) &player) + 0xD78); // TODO: Do the f*** header of Entity, Mob, Player. ItemInstance* instance = player.getSelectedItem(); if(container->itemInstance == nullptr && instance != nullptr) { container->maxItems = instance->getMaxStackSize() * 64; container->itemCount = instance->count; container->itemInstance = ItemInstance::clone(instance); playerInventory->clearSlot(playerInventory->getSelectedSlot()); } else if((instance == nullptr || instance->getId() != container->itemInstance->getId()) && container->itemCount > 0) { ItemInstance temp(container->itemInstance->getId(), 1, container->itemInstance->getAuxValue()); if(!playerInventory->add(temp)) // This function clone the ItemInstance { //If the player does not have space, drop the item to the floor. player.region.getLevel()->addEntity(std::unique_ptr<Entity>(new ItemEntity(player.region, Vec3(pos), temp, 1))); } container->itemCount -= 1; } else if(container->itemInstance->sameItemAndAux(instance) && (container->itemCount > 0) && (container->itemCount < container->maxItems)) { if((container->itemCount + instance->count) > container->maxItems) { instance->count = (container->itemCount + instance->count) - container->maxItems; container->itemCount = container->maxItems; } else { container->itemCount += instance->count; playerInventory->clearSlot(playerInventory->getSelectedSlot()); } } container->setChanged(); if(container->itemCount <= 0) container->clear(); if(instance == nullptr) return false; return true; }
//----[ isCarrying ]--------------------------------------------------------- bool ClientItemsInterface::isCarrying(unsigned int item_type, int quantity) { for (unsigned int i = 0; i < items_in_inventory_; ++i) { ItemInstance* item = inventory_[i].item.dereference(); if (!item) { repackInventory(); return false; } else { if (item->getDescription()->type_index == item_type) { quantity -= item->getQuantity(); if (quantity <= 0) return true; } } } return false; }
//----[ setInventoryItem ]--------------------------------------------------- void ClientItemsInterface::setInventoryItem(unsigned int index, ItemPointer& item_pointer) { ItemInstance* item = item_pointer.dereferenceAssumingValid(); inventory_[index].item.copy(item_pointer); inventory_[index].stackable = item->isStackable(); inventory_[index].equipped = false; inventory_dirty_bits_.set(index); update_inventory_ = true; { // become the owner of this item //inventory_[index].item.becomeUniquePointer(); GlobalDatabaseManager::singleton()->itemChangeOwner(item->getUniqueID(), account_id_, character_id_, session_id_); } }
void EQEmu::ItemInstance::PutItem(uint8 index, const ItemInstance& inst) { // Clean up item already in slot (if exists) DeleteItem(index); // Delegate to internal method _PutItem(index, inst.Clone()); }
//----[ isCarryingNew ]------------------------------------------------------ bool ClientItemsInterface::isCarryingNew(unsigned int item_type, int quantity, ItemIDType oldest_id) { for (unsigned int i = 0; i < items_in_inventory_; ++i) { ItemInstance* item = inventory_[i].item.dereference(); if (!item) { repackInventory(); return false; } else { if (item->getDescription()->type_index == item_type && item->getUniqueID() >= oldest_id) { // consider only new items quantity -= item->getQuantity(); if (quantity <= 0) return true; } } } return false; }
int QualityBasedMiningToolItemTypeComponent::getPower(const ItemInstance& itemInstance) const { if(_strengths.size() == 0) { return 0; } ItemInstanceComponent* comp = itemInstance.getComponent(ItemInstanceComponent::QualityItemInstanceComponent); int quality = comp == 0 ? 0 : static_cast<QualityItemInstanceComponent*>(comp)->getQualityValue(); return quality < 0 ? _strengths.front() : quality >= _strengths.size() ? _strengths.back() : _strengths[quality]; }
void Room::initializeFromFile(std::ifstream& fin, std::vector<Monster>& temp, std::vector<Items>& temp2, int level) { initialized = true; fin >> width; fin >> height; int nMonsters; fin >> nMonsters; for (int i = 0; i < nMonsters; i++) { std::string name; fin >> name; MonsterInstance* m = 0; for (int i = 0; i < temp.size(); i++) { if (!name.compare(temp[i].getName())) m = new MonsterInstance(temp[i]); } if (m == 0) throw "bad monster name"; int x, y; fin >> x; fin >> y; m->setCoords(x, y); monsters.push_back(*m); } int nItems; fin >> nItems; for (int i = 0; i < nItems; i++) { std::string name; fin >> name; ItemInstance* m = 0; for (int i = 0; i < temp2.size(); i++) { if (!name.compare(temp2[i].getName())) m = new ItemInstance(temp2[i]); } if (m == 0) throw "bad item name"; int x, y; fin >> x; fin >> y; m->setCoords(x, y); items.push_back(*m); } }
//----[ giveItem ]----------------------------------------------------------- bool ClientItemsInterface::giveItem(ItemPointer* item_pointer, unsigned int* assigned_index) { if (!item_pointer || item_pointer->invalid()) return false; ItemInstance* item = item_pointer->dereferenceAssumingValid(); // justified by prev. line int source_quantity = item->getQuantity(); if (source_quantity < 0) return false; // stack with existing items if (item->isStackable()) { unsigned int start_search_index = 0; while (item && start_search_index < items_in_inventory_) { // keep the index safe! ItemInstance* stackable_item = NULL; if (!findStackableItemInInventory(item, start_search_index, &start_search_index, &stackable_item)) break; inventory_dirty_bits_.set(start_search_index); update_inventory_ = true; ++start_search_index; item->setQuantity(stackable_item->addQuantity(item->getQuantity())); if (item->getQuantity() <= 0) { GlobalItemManager::singleton()->releaseItem(item_pointer); item = NULL; } } } // add to the inventory return item ? addToInventory(*item_pointer, assigned_index) : true; }
//----[ consumeItem ]-------------------------------------------------------- bool ClientItemsInterface::consumeItem(unsigned int index, Magic::MagicIndex* magic_index) { assert(magic_index); if (!inventoryItemIsValid(index)) return false; ItemInstance* item = inventory_[index].item.dereferenceAssumingValid(); // guaranteed OK const Item::ItemServerDescription* description = item->getDescription(); if (description->consumable_magic == Magic::INVALID_MAGIC_INDEX) return false; *magic_index = description->consumable_magic; if (item->removeQuantity(1) >= 0) { // this item has been fully consumed GlobalDatabaseManager::singleton()->itemOnAvatarErased(item->getUniqueID()); GlobalItemManager::singleton()->releaseItem(&inventory_[index].item); shiftDownToEraseInInventory(index); } else { // item is still available update_inventory_ = true; inventory_dirty_bits_.set(index); } todo("karl","if equipped consumable and consumed, change equipment"); return true; }
void Room::initializeRandom(std::vector<Monster>& tempM, std::vector<Items>& tempI, int level) { initialized = true; width = 5 + rand() % 5; height = 5 + rand() % 5; int nMonsters = maxMonsters != 0?rand() % maxMonsters:0; std::vector<Monster> vm; for (int i = 0; i < tempM.size(); i++) { if (tempM[i].getScale() <= level) vm.push_back(tempM[i]); } for (int i = 0; i < nMonsters; i++) { MonsterInstance m(vm[rand() % vm.size()]); m.setCoords(rand() % width, rand() % height); monsters.push_back(m); } int nItems = rand() % maxItems; std::vector<Items> wal; std::vector<Items> ol; for (int i = 1; i < tempI.size(); i++) { if (tempI[i].getType() == 2) { if (tempI[i].getScale() <= level) ol.push_back(tempI[i]); } else if (tempI[i].getScale() <= level) wal.push_back(tempI[i]); } for (int i = 0; i < nItems; i++) { ItemInstance* m; if (rand() % 100 < 20) { m = new ItemInstance(wal[rand() % wal.size()]); } else { m = new ItemInstance(ol[rand() % ol.size()]); } m->setCoords(rand() % width, rand() % height); items.push_back(*m); } }
//----[ changeEquipped ]----------------------------------------------------- bool ClientItemsInterface::changeEquipped(unsigned int item_index) { if (!inventoryItemIsValid(item_index)) return false; ItemInstance* item = inventory_[item_index].item.dereference(); int quantity = item->getQuantity(); if (!canHoldItems(1) && quantity > 1) return false; equipment_changed_ = true; inventory_[item_index].equipped = !inventory_[item_index].equipped; update_inventory_ = true; inventory_dirty_bits_.set(item_index); if (quantity > 1) { int quantity_to_remove = quantity - 1; item->removeQuantity(quantity_to_remove); ItemPointer new_item; bool succeeded = false; if (GlobalItemManager::singleton()->acquireNewItem( quantity_to_remove, item->getDescription()->type_index, &new_item)) { unsigned int new_index; if (giveItem(&new_item, &new_index)) { succeeded = true; } } if (!succeeded) { // put the quantity back since this new item doesn't exist item->addQuantity(quantity_to_remove); // make the item unequipped inventory_[item_index].equipped = false; } } return true; }
Void CharStatPackage::_ComputePersistentStatModifiers() { // Modifiers from passives for( UInt i = 0; i < CHARSTAT_COUNT; ++i ) m_arrPassiveStatModifier[i] = 0.0f; m_pOwner->EnumSkills(); SkillInstance * pSkillInstance = m_pOwner->EnumNextSkill(); while( pSkillInstance != NULL ) { if ( pSkillInstance->IsPassive() ) { const Scalar * arrBonus = ( (PassiveSkill*)(pSkillInstance->GetSkill()) )->GetStatBonus(); for( UInt i = 0; i < CHARSTAT_COUNT; ++i ) m_arrPassiveStatModifier[i] += arrBonus[i]; } pSkillInstance = m_pOwner->EnumNextSkill(); } // Modifiers from items for( UInt i = 0; i < CHARSTAT_COUNT; ++i ) m_arrItemStatModifier[i] = 0.0f; for( UInt i = 0; i < EQUIPSLOTID_COUNT; ++i ) { ItemInstance * pItemInstance = m_pOwner->GetItem( (EquipmentSoltID)i ); if ( pItemInstance->IsEmpty() ) continue; Assert( pItemInstance->GetItem()->GetType() == ITEMTYPE_EQUIPMENT ); EquipmentItem * pItem = (EquipmentItem*)( pItemInstance->GetItem() ); const Scalar * arrBonus = pItem->GetStatBonus(); for( UInt j = 0; j < CHARSTAT_COUNT; ++j ) m_arrItemStatModifier[j] += arrBonus[j]; } // Final stats for( UInt i = 0; i < CHARSTAT_COUNT; ++i ) m_arrFinalStat[i] = ( m_arrModdedStat[i] + m_arrPassiveStatModifier[i] + m_arrItemStatModifier[i] ); }
void PickaxeItem::hurtEnemy(ItemInstance &item, Mob*, Mob *victim) const { item.hurtAndBreak(2, victim); }
// Remove all items from container void EQEmu::ItemInstance::ClearByFlags(byFlagSetting is_nodrop, byFlagSetting is_norent) { // TODO: This needs work... // Destroy container contents std::map<uint8, ItemInstance*>::const_iterator cur, end, del; cur = m_contents.begin(); end = m_contents.end(); for (; cur != end;) { ItemInstance* inst = cur->second; if (inst == nullptr) { cur = m_contents.erase(cur); continue; } const ItemData* item = inst->GetItem(); if (item == nullptr) { cur = m_contents.erase(cur); continue; } del = cur; ++cur; switch (is_nodrop) { case byFlagSet: if (item->NoDrop == 0) { safe_delete(inst); m_contents.erase(del->first); continue; } // no 'break;' deletes 'byFlagNotSet' type - can't add at the moment because it really *breaks* the process somewhere case byFlagNotSet: 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; } // no 'break;' deletes 'byFlagNotSet' type - can't add at the moment because it really *breaks* the process somewhere case byFlagNotSet: if (item->NoRent != 0) { safe_delete(inst); m_contents.erase(del->first); continue; } default: break; } } }
bool PickaxeItem::mineBlock(ItemInstance &item, BlockID, int, int, int, Entity *entity) const { item.hurtAndBreak(1, entity); }
ItemInstance * Inventory::EquipItem( EquipmentSoltID idEquipSlot, InventoryBagID idBag, UInt iSlot ) { Assert( idBag < INVENTORYBAGID_COUNT && iSlot < INVENTORY_BAG_SIZE ); ItemInstance * pSwap = m_arrBags[idBag].arrSlots[iSlot]; if ( pSwap == NULL ) return NULL; switch( idEquipSlot ) { case EQUIPSLOTID_HEAD: if ( pSwap->GetClass() != ITEMCLASS_HEAD ) return NULL; break; case EQUIPSLOTID_CHEST: if ( pSwap->GetClass() != ITEMCLASS_CHEST ) return NULL; break; case EQUIPSLOTID_SHOULDERS: if ( pSwap->GetClass() != ITEMCLASS_SHOULDERS ) return NULL; break; case EQUIPSLOTID_ARMS: if ( pSwap->GetClass() != ITEMCLASS_ARMS ) return NULL; break; case EQUIPSLOTID_WRISTS: if ( pSwap->GetClass() != ITEMCLASS_WRISTS ) return NULL; break; case EQUIPSLOTID_HANDS: if ( pSwap->GetClass() != ITEMCLASS_HANDS ) return NULL; break; case EQUIPSLOTID_LEGS: if ( pSwap->GetClass() != ITEMCLASS_LEGS ) return NULL; break; case EQUIPSLOTID_FEET: if ( pSwap->GetClass() != ITEMCLASS_FEET ) return NULL; break; case EQUIPSLOTID_NECK: if ( pSwap->GetClass() != ITEMCLASS_NECK ) return NULL; break; case EQUIPSLOTID_BELT: if ( pSwap->GetClass() != ITEMCLASS_BELT ) return NULL; break; case EQUIPSLOTID_RING_1: case EQUIPSLOTID_RING_2: if ( pSwap->GetClass() != ITEMCLASS_RING ) return NULL; break; case EQUIPSLOTID_TRINKET_1: case EQUIPSLOTID_TRINKET_2: if ( pSwap->GetClass() != ITEMCLASS_TRINKET ) return NULL; break; case EQUIPSLOTID_TOOL_RIGHT: if ( pSwap->GetClass() != ITEMCLASS_TOOL_RIGHT ) return NULL; break; case EQUIPSLOTID_TOOL_LEFT: if ( pSwap->GetClass() != ITEMCLASS_TOOL_LEFT ) return NULL; break; case EQUIPSLOTID_TOOL_DISTANCE: if ( pSwap->GetClass() != ITEMCLASS_TOOL_DISTANCE ) return NULL; break; case EQUIPSLOTID_WEAPON_RIGHT: if ( pSwap->GetClass() != ITEMCLASS_WEAPON_RIGHT ) return NULL; break; case EQUIPSLOTID_WEAPON_LEFT: if ( pSwap->GetClass() != ITEMCLASS_WEAPON_LEFT ) return NULL; break; case EQUIPSLOTID_WEAPON_DISTANCE: if ( pSwap->GetClass() != ITEMCLASS_WEAPON_DISTANCE ) return NULL; break; default: Assert(false); break; } if ( pSwap->GetBindType() == ITEMBIND_ON_EQUIP ) pSwap->Bind(); m_arrBags[idBag].arrSlots[iSlot] = m_arrEquipmentSlots[idEquipSlot]; m_arrEquipmentSlots[idEquipSlot] = pSwap; return pSwap; }
//----[ dropItemsOnDeath ]--------------------------------------------------- void ClientItemsInterface::dropItemsOnDeath(int equipped_items_to_drop, Map* map, int x, int y) { WorldRegion* region = map->acquireRegionFromPoint(x, y); if (!region || (items_in_inventory_ == 0)) return; // equipped items are temporarily listed here kg::Array<AvatarInventoryItem,AVATAR_INVENTORY_SIZE> items_not_dropped; // drop all inventory items and count the equipped items for (unsigned int i = 0; i < items_in_inventory_; ++i) { ItemInstance* item = inventory_[i].item.dereference(); confirm(item) else continue; if (!item->getDescription()->drop_on_death || inventory_[i].equipped) { items_not_dropped.add(inventory_[i]); } else { region->addItemOnGround(true, x, y, inventory_[i].item); } inventory_[i].item.reset(); inventory_[i].stackable = false; inventory_[i].equipped = false; } // NOTE: items_in_inventory_ (the private member variable) will hold // the OLD number of items until the end of this method--so // don't touch it! this is so that we can tell if the # of items // changed. // move non-drop items back into the inventory unsigned int items_in_inventory = 0; for (unsigned int i = 0; i < items_not_dropped.count;) { ItemInstance* item = items_not_dropped[i].item.dereference(); if (!item->getDescription()->drop_on_death) { memcpy(&inventory_[items_in_inventory], &items_not_dropped[i], sizeof(AvatarInventoryItem)); ++items_in_inventory; items_not_dropped[i].item.reset(); items_not_dropped.swapRemoveMemcpy(i); } else { ++i; } } // drop equipped items if (equipped_items_to_drop >= items_not_dropped.count) { // drop everything for (unsigned int i = 0; i < items_not_dropped.count;) { ItemInstance* item = items_not_dropped[i].item.dereference(); region->addItemOnGround(true, x, y, items_not_dropped[i].item); items_not_dropped[i].item.reset(); items_not_dropped.swapRemoveMemcpy(i); } } else { // randomly pick items to drop int number_of_items_dropped = 0; while (number_of_items_dropped < equipped_items_to_drop) { confirm(items_not_dropped.count > 0) else break; int slot = rand()%items_not_dropped.count; ItemInstance* item = items_not_dropped[slot].item.dereference(); region->addItemOnGround(true, x, y, items_not_dropped[slot].item); items_not_dropped[slot].item.reset(); items_not_dropped.swapRemoveMemcpy(slot); ++number_of_items_dropped; } } // move items that weren't dropped back into the inventory for (unsigned int i = 0; i < items_not_dropped.count; ++i) { ItemInstance* item = items_not_dropped[i].item.dereference(); memcpy(&inventory_[items_in_inventory], &items_not_dropped[i], sizeof(AvatarInventoryItem)); // If the item provides on-death magic, ensure it is no longer // equipped. This causes Valtus Mederi Charms and the like to // only prevent death once (until the user can get back up and // re-equip one) even if multiple are equipped. if (item->getDescription()->on_death_magic != Magic::INVALID_MAGIC_INDEX) { inventory_[items_in_inventory].equipped = false; } ++items_in_inventory; } /* // drop all inventory items and count the equipped items unsigned int first_remaining_item = AVATAR_INVENTORY_SIZE, last_remaining_item = 0; for (unsigned int i = 0; i < items_in_inventory_; ++i) { ItemInstance* item = inventory_[i].item.dereference(); assert(item); if (!item->getDescription()->drop_on_death || inventory_[i].equipped) { if (i < first_remaining_item) first_remaining_item = i; last_remaining_item = i; } else { region->addItemOnGround(true, x, y, inventory_[i].item); inventory_[i].item.reset(); inventory_[i].stackable = false; } } // will hold the number of items left in the inventory int items_in_inventory = 0; // copy down remaining equipped items for (unsigned int i = first_remaining_item; i <= last_remaining_item; ++i) { if (inventory_[i].item.invalid()) continue; assert(inventory_[i].equipped || !inventory_[i].item.dereference()->getDescription()->drop_on_death); if (i != items_in_inventory) { memcpy(&inventory_[items_in_inventory], &inventory_[i], sizeof(AvatarInventoryItem)); } ++items_in_inventory; } if (equipped_items_to_drop >= items_in_inventory) { int items_remaining = 0; // drop everything; leave nothing (except non-drop items) for (unsigned int i = 0; i < items_in_inventory; ++i) { ItemInstance* item = inventory_[i].item.dereference(); assert(item); if (item->getDescription()->drop_on_death) { equipment_changed_ = true; region->addItemOnGround(true, x, y, inventory_[i].item); inventory_[i].item.reset(); inventory_[i].stackable = false; inventory_[i].equipped = false; } else { if (i != items_remaining) { memcpy(&inventory_[items_remaining], &inventory_[i], sizeof(AvatarInventoryItem)); } ++items_remaining; } } items_in_inventory = items_remaining; } else { // go in a loop assert(items_in_inventory > 0); int first_item = rand()%items_in_inventory; int i = first_item; int number_of_items_dropped = 0; do { ItemInstance* item = inventory_[i].item.dereference(); assert(item); if (item->getDescription()->drop_on_death) { assert(inventory_[i].equipped); region->addItemOnGround(true, x, y, inventory_[i].item); inventory_[i].item.reset(); inventory_[i].stackable = false; inventory_[i].equipped = false; ++number_of_items_dropped; } i = (i + 1) % items_in_inventory; } while (i != first_item && (number_of_items_dropped < equipped_items_to_drop)); // copy down all remaining valid items, but unequip them // if they gave on-death magic int remaining_items = 0; for (int j = 0; j < items_in_inventory; ++j) { if (inventory_[j].item.invalid() == false) { if (inventory_[j].item.dereference()->getDescription()->on_death_magic != Magic::INVALID_MAGIC_INDEX) { // this should cause Valtus Mederi Charms and other special // items to unequip themselves when a character dies, but // it will leave all non-dropped equipment on the character inventory_[j].equipped = false; } if (j != remaining_items) { memcpy(&inventory_[remaining_items], &inventory_[j], sizeof(AvatarInventoryItem)); ++remaining_items; } } } items_in_inventory_ = remaining_items; } */ // did anything change? if (items_in_inventory != items_in_inventory_) { equipment_changed_ = true; region->broadcastUpdateItemsOnLocation(x, y); inventory_dirty_bits_.setRange(0, items_in_inventory_); items_in_inventory_ = items_in_inventory; commit(); } }