Example #1
0
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;
}
Example #2
0
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;
}
Example #3
0
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;
}
Example #5
0
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);
}
Example #6
0
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;
}
Example #7
0
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;
}