bool CInventory::ReplaceItem(idEntity* oldItemEnt, idEntity* newItemEnt) { if (oldItemEnt == NULL) return false; idStr oldInvName = oldItemEnt->spawnArgs.GetString("inv_name"); CInventoryItemPtr oldItem = GetItem(oldInvName); if (oldItem == NULL) { gameLocal.Warning("Could not find old inventory item for %s", oldItemEnt->name.c_str()); DM_LOG(LC_INVENTORY, LT_DEBUG)LOGSTRING("Could not find old inventory item for %s\n", oldItemEnt->name.c_str()); return false; } // greebo: Let's call PutItem on the new entity first to see what kind of item this is // PutItem will also take care of the mission data callbacks for the objectives CInventoryItemPtr newItem = PutItem(newItemEnt, m_Owner.GetEntity()); if (newItem != NULL && newItem->Category() == oldItem->Category()) { // New item has been added, swap the old and the new one to fulfil the inventory position guarantee oldItem->Category()->SwapItemPosition(oldItem, newItem); } // If SwapItemPosition has been called, newItem now takes the place of oldItem before the operation. // Remove the old item in any case, but only if the items are actually different. // In case anybody wonder, newItem might be the same as oldItem in the case of stackable items or loot. if (oldItem != newItem) { RemoveItem(oldItem); } return true; }
int CShop::GetQuantityForItem(const CInventoryItemPtr& item) { int quantity = item->GetPersistentCount(); // Check if this is a weapon CInventoryWeaponItemPtr weaponItem = boost::dynamic_pointer_cast<CInventoryWeaponItem>(item); bool isWeapon = (weaponItem != NULL); if (isWeapon) { // Use the ammonition for weapon items if (weaponItem->NeedsAmmo()) { quantity = weaponItem->GetAmmo(); } else { // Non-ammo weapons need to be enabled to be added quantity = weaponItem->IsEnabled() ? 1 : 0; } } return quantity; }
void CInventory::PutItem(const CInventoryItemPtr& item, const idStr& categoryName) { if (item == NULL) return; CInventoryCategoryPtr category; // Check if it is the default group or not. if (categoryName.IsEmpty()) { // category is empty, assign the item to the default group category = m_Category[0]; } else { // Try to find the category with the given name category = GetCategory(categoryName); // If not found, create it if (category == NULL) { category = CreateCategory(categoryName); } } // Pack the item into the category category->PutItemFront(item); // Objective callback for non-loot items: // non-loot item passes in inv_name and individual item count, SuperGroupVal of 1 gameLocal.m_MissionData->InventoryCallback( item->GetItemEntity(), item->GetName(), item->GetCount(), 1, true ); }
bool CFrobLock::CanBeUsedBy(const CInventoryItemPtr& item, const bool isFrobUse) { // First, check if the frob master can be used // If this doesn't succeed, perform additional checks idEntity* master = GetFrobMaster(); if( master != NULL && master->CanBeUsedBy(item, isFrobUse) ) { return true; } if (item == NULL) return false; assert(item->Category() != NULL); const idStr& categoryName = item->Category()->GetName(); if (categoryName == "#str_02392" ) // Keys { // Keys can always be used on doors // Exception: for "frob use" this only applies when the mover is locked return (isFrobUse) ? IsLocked() : true; } else if (categoryName == "#str_02389" ) // Lockpicks { if (!m_Lock->IsPickable()) { // Lock is not pickable DM_LOG(LC_LOCKPICK, LT_DEBUG)LOGSTRING("FrobLock %s is not pickable\r", name.c_str()); return false; } // Lockpicks behave similar to keys return (isFrobUse) ? IsLocked() : true; } return false; }
void CInventory::RemoveItem(const CInventoryItemPtr& item) { if (item == NULL) return; // Update the cursors first for (int i = 0; i < m_Cursor.Num(); i++) { if (m_Cursor[i]->GetCurrentItem() == item) { // Advance the cursor, this should be enough m_Cursor[i]->GetNextItem(); } } // Now remove the item, the cursors are updated. item->Category()->RemoveItem(item); }
CInventoryItemPtr CInventory::PutItem(idEntity *ent, idEntity *owner) { // Sanity checks if (ent == NULL || owner == NULL) return CInventoryItemPtr(); // grayman (#2376) - If there's a shop with this item in it, // and this is an inv_map_start item, we won't put it into the // inventory because the player already has it. const ShopItemList& startingItems = gameLocal.m_Shop->GetPlayerStartingEquipment(); bool gotFromShop = ((startingItems.Num() > 0) && (ent->spawnArgs.GetBool("inv_map_start", "0"))); // Check for loot items CInventoryItemPtr returnValue = ValidateLoot(ent,gotFromShop); // grayman (#2376) if (ent->GetAbsenceNoticeability() > 0) { ent->SpawnAbsenceMarker(); } if (returnValue != NULL) { // The item is a valid loot item, remove the entity and return DM_LOG(LC_INVENTORY, LT_DEBUG)LOGSTRING("Added loot item to inventory: %s\r", ent->name.c_str()); // Remove the entity, it is a loot item (which vanishes when added to the inventory) RemoveEntityFromMap(ent, true); return returnValue; } // Let's see if this is an ammunition item returnValue = ValidateAmmo(ent,gotFromShop); // grayman (#2376) if (returnValue != NULL) { DM_LOG(LC_INVENTORY, LT_DEBUG)LOGSTRING("Added ammo item to inventory, removing from map: %s\r", ent->name.c_str()); // Remove the entity from the game, the ammunition is added RemoveEntityFromMap(ent, true); return returnValue; } // Check for a weapon item returnValue = ValidateWeapon(ent,gotFromShop); // grayman (#2376) if (returnValue != NULL) { DM_LOG(LC_INVENTORY, LT_DEBUG)LOGSTRING("Added weapon item to inventory, removing from map: %s\r", ent->name.c_str()); // Remove the entity from the game, the ammunition is added RemoveEntityFromMap(ent, true); return returnValue; } // Not a loot or ammo item, determine name and category to check for existing item of same name/category idStr name = ent->spawnArgs.GetString("inv_name", ""); idStr category = ent->spawnArgs.GetString("inv_category", ""); // Tels: Replace "\n" with \x0a, otherwise multiline spawnargs set inside DR do not work name.Replace( "\\n", "\n" ); category.Replace( "\\n", "\n" ); if (name.IsEmpty() || category.IsEmpty()) { // Invalid inv_name or inv_category DM_LOG(LC_INVENTORY, LT_ERROR)LOGSTRING("Cannot put %s in inventory: inv_name or inv_category not specified.\r", ent->name.c_str()); return returnValue; } // Check for existing items (create the category if necessary (hence the TRUE)) CInventoryItemPtr existing = GetItem(name, category, true); if (existing != NULL) { // Item must be stackable, if items of the same name/category already exist if (!ent->spawnArgs.GetBool("inv_stackable", "0")) { DM_LOG(LC_INVENTORY, LT_ERROR)LOGSTRING("Cannot put %s in inventory: not stackable.\r", ent->name.c_str()); // grayman #2467 - Remove the entity from the game if it was already put into the inventory by the shop code. if (gotFromShop) { RemoveEntityFromMap(ent, true); } return returnValue; } // Item is stackable, determine how many items should be added to the stack int count = ent->spawnArgs.GetInt("inv_count", "1"); // grayman (#2376) - If there's a shop in this mission, all stackable inv_map_start items were shown in // the shop's startingItems list, and have already been given to the player. Check if this // entity is an inv_map_start entity. If it is, check the size of the startingItems list. // If it's 0, then there's no shop and we have to give the player the count from this // entity. If > 0, zero the count because the player already has it. if (gotFromShop) { count = 0; // Item count already given, so clear it. } // Increase the stack count existing->SetCount(existing->GetCount() + count); // Persistent flags are latched - once a inv_persistent item is added to a stack, the whole stack // snaps into persistent mode. if (ent->spawnArgs.GetBool("inv_persistent") && !existing->IsPersistent()) { DM_LOG(LC_INVENTORY, LT_DEBUG)LOGSTRING("Marking stackable items as persistent after picking up one persistent item: %s\r", existing->GetName().c_str()); existing->SetPersistent(true); } // We added a stackable item that was already in the inventory // grayman #3315 - Solution from Zbyl. InventoryCallback() looks at // the existing entity to retrieve a bindmaster, and that's already // been NULLed. So we need to look at the new entity instead. gameLocal.m_MissionData->InventoryCallback( ent, existing->GetName(), existing->GetCount(), 1, true ); // Notify the player, if appropriate // grayman #3316 - correct pickup message, courtesy Zbyl if ( !ent->spawnArgs.GetBool("inv_map_start", "0") && !ent->spawnArgs.GetBool("inv_no_pickup_message", "0") ) { idStr msg = common->Translate(name); if ( count > 1 ) { msg += " x" + idStr(count); } NotifyOwnerAboutPickup(msg, existing); } DM_LOG(LC_INVENTORY, LT_DEBUG)LOGSTRING("Added stackable item to inventory: %s\r", ent->name.c_str()); DM_LOG(LC_INVENTORY, LT_DEBUG)LOGSTRING("New inventory item stack count is: %d\r", existing->GetCount()); // Remove the entity, it has been stacked RemoveEntityFromMap(ent, true); // Return the existing value instead of a newly created one returnValue = existing; } else { // Item doesn't exist, create a new InventoryItem // grayman (#2376) - if we got here, the item isn't already in the inventory, // so it wasn't given by the shop. No code changes needed. CInventoryItemPtr item(new CInventoryItem(ent, owner)); if (item != NULL) { DM_LOG(LC_INVENTORY, LT_DEBUG)LOGSTRING("Adding new inventory item %s to category %s...\r", common->Translate(name.c_str()), common->Translate(category.c_str())); // Put the item into its category PutItem(item, category); // grayman #3313 - Solution is from Zbyl. InventoryCallback() is called from PutItem(), so it's already been done. /* // We added a new inventory item gameLocal.m_MissionData->InventoryCallback( item->GetItemEntity(), item->GetName(), 1, 1, true ); */ // grayman #3316 - correct pickup message, courtesy Zbyl if ( !ent->spawnArgs.GetBool("inv_map_start", "0") && !ent->spawnArgs.GetBool("inv_no_pickup_message", "0") ) { idStr msg = common->Translate(name); if ( item->GetCount() > 1 ) { msg += " x" + idStr(item->GetCount()); } NotifyOwnerAboutPickup(msg, item); } // Hide the entity from the map (don't delete the entity) RemoveEntityFromMap(ent, false); } else { DM_LOG(LC_INVENTORY, LT_ERROR)LOGSTRING("Cannot put item into category: %s.\r", ent->name.c_str()); } returnValue = item; } return returnValue; }
CInventoryItemPtr CInventory::ValidateLoot(idEntity *ent, const bool gotFromShop) // grayman (#2376) { CInventoryItemPtr rc; int LGroupVal = 0; int dummy1(0), dummy2(0), dummy3(0); // for calling GetLoot LootType lootType = CInventoryItem::GetLootTypeFromSpawnargs(ent->spawnArgs); int value = ent->spawnArgs.GetInt("inv_loot_value", "-1"); // grayman (#2376) - if anyone ever marks loot "inv_map_start" and it's a valid shop // item, the player inventory will already have it at this point. if (gotFromShop) { value = -1; } if (lootType != LOOT_NONE && value > 0) { idStr pickedUpMsg = idStr(value); // If we have an anonymous loot item, we don't need to // store it in the inventory. switch (lootType) { case LOOT_GOLD: m_Gold += value; LGroupVal = m_Gold; pickedUpMsg += common->Translate("#str_07320"); // " in Gold" break; case LOOT_GOODS: m_Goods += value; LGroupVal = m_Goods; pickedUpMsg += common->Translate("#str_07321"); // " in Goods" break; case LOOT_JEWELS: m_Jewelry += value; LGroupVal = m_Jewelry; pickedUpMsg += common->Translate("#str_07322"); // " in Jewels" break; default: break; } m_LootItemCount++; rc = GetItemByType(CInventoryItem::IT_LOOT_INFO); assert(rc != NULL); // the loot item must exist // greebo: Update the total loot value in the objectives system BEFORE // the InventoryCallback. Some comparisons rely on a valid total loot value. gameLocal.m_MissionData->ChangeFoundLoot(lootType, value); // Objective Callback for loot on a specific entity: // Pass the loot type name and the net loot value of that group gameLocal.m_MissionData->InventoryCallback( ent, sLootTypeName[lootType], LGroupVal, GetLoot( dummy1, dummy2, dummy3 ), true ); // Take the loot icon of the picked up item and use it for the loot stats item idStr lootIcon = ent->spawnArgs.GetString("inv_icon"); if (rc != NULL && !lootIcon.IsEmpty()) { rc->SetIcon(lootIcon); } if (!ent->spawnArgs.GetBool("inv_map_start", "0") && !ent->spawnArgs.GetBool("inv_no_pickup_message", "0")) { NotifyOwnerAboutPickup(pickedUpMsg, rc); } } else { DM_LOG(LC_STIM_RESPONSE, LT_ERROR)LOGSTRING("Item %s doesn't have an inventory name and is not anonymous.\r", ent->name.c_str()); } return rc; }
bool CFrobLock::UseBy(EImpulseState impulseState, const CInventoryItemPtr& item) { if (item == NULL) return false; // Pass the call on to the master, if we have one if (GetFrobMaster() != NULL) { return GetFrobMaster()->UseBy(impulseState, item); } assert(item->Category() != NULL); // Retrieve the entity behind that item and reject NULL entities idEntity* itemEntity = item->GetItemEntity(); if (itemEntity == NULL) return false; // Get the name of this inventory category const idStr& categoryName = item->Category()->GetName(); if (categoryName == "#str_02392" && impulseState == EPressed ) // Keys { // Keys can be used on button PRESS event, let's see if the key matches if (m_UsedByName.FindIndex(itemEntity->name) != -1) { // just toggle the lock. ToggleLock(); return true; } else { FrobLockStartSound("snd_wrong_key"); return false; } } else if (categoryName == "#str_02389" ) // Lockpicks { if (!m_Lock->IsPickable()) { // Lock is not pickable DM_LOG(LC_LOCKPICK, LT_DEBUG)LOGSTRING("FrobLock %s is not pickable\r", name.c_str()); return false; } // First we check if this item is a lockpick. It has to be of correct type idStr str = itemEntity->spawnArgs.GetString("lockpick_type", ""); if (str.Length() == 1) { // greebo: Check if the item owner is a player, and if yes, // update the immobilization flags. idEntity* itemOwner = item->GetOwner(); if (itemOwner->IsType(idPlayer::Type)) { idPlayer* playerOwner = static_cast<idPlayer*>(itemOwner); playerOwner->SetImmobilization("Lockpicking", EIM_ATTACK); // Schedule an event 1/3 sec. from now, to enable weapons again after this time CancelEvents(&EV_TDM_FrobLock_ClearPlayerImmobilization); PostEventMS(&EV_TDM_FrobLock_ClearPlayerImmobilization, 300, playerOwner); } // Pass the call to the lockpick routine return m_Lock->ProcessLockpickImpulse(impulseState, static_cast<int>(str[0])); } else { gameLocal.Warning("Wrong 'lockpick_type' spawnarg for lockpicking on item %s, must be a single character.", itemEntity->name.c_str()); return false; } } return false; }