Reputation: 23
I'm struggling with one piece of code and I was wondering if anyone could help me.
Here's my problem:
I'm working on a game and I created an inventory with a Dictionary. My Dictionary TKey is the item name and the TValue is a List. Each items has a boolean "isEquipped".
Dictionary<string, List<Item>> itemsInventory;
When equipping an item I want to check if the player has enough of this item and if this item can be equipped. I do that with this code:
public void EquipWeapon(bool tog, Item item)
{
if (tog == true)
{
if (player.weapon == false)
{
player.GetStatByName(item.StatAffectedName).AddModifier(item.StatAffectedValue, StatModifier.ModifierOrigins.Equipment, StatModifier.ModifierType.Flat, item.AssetName);
GameManagerSingleton.Instance.PlayerData.itemsInventory.FirstOrDefault(x => x.Key == item.AssetName && x.Value.Any(x => x.isEquiped == false)).Value.FirstOrDefault().isEquiped = true;
}
}
else
{
if (player.weapon == true)
{
player.GetStatByName(item.StatAffectedName).RemoveModifier(item.AssetName);
GameManagerSingleton.Instance.PlayerData.itemsInventory.FirstOrDefault(x => x.Key == item.AssetName && x.Value.Any(x => x.isEquiped == true)).Value.FirstOrDefault().isEquiped = false;
}
player.weapon = false;
}
player.GetStatByName(item.StatAffectedName).GetValue();
}
Problem with my code is that it changes all the items of the list and not just one. Anyone could help me please?
Upvotes: 0
Views: 254
Reputation: 23
My code looked like this :
public void AddItemToInventory(Item? item, Ressource? ressource, int number = 1)
{
if (item != null)
{
int totalPrice = (item.Price * number);
ressources.First(x => x.currency == item.Currency).amount -= totalPrice;
DailyReportHandler.GetAndFillTodayReport().moneyForItems += totalPrice;
if (itemsInventory.ContainsKey(item.AssetName))
{
for (int i = 0; i < number; i++)
{
itemsInventory.FirstOrDefault(x => x.Key == item.AssetName).Value.Add(item);
}
}
else
{
itemsInventory.Add(item.AssetName, new List<Item>());
for (int i = 0; i < number; i++)
{
itemsInventory.FirstOrDefault(x => x.Key == item.AssetName).Value.Add(item);
}
}
}
if (ressource != null)
{
int totalPrice = (ressource.price * number);
ressources.First(x => x.currency == Currency.credit).amount -= totalPrice;
DailyReportHandler.GetAndFillTodayReport().moneyForItems += totalPrice;
GameManagerSingleton.Instance.PlayerData.AddResource(ressource.currency, number);
}
}
and I change it to this:
public void AddItemToInventory(Item? item, Ressource? ressource, int number = 1)
{
if (item != null)
{
int totalPrice = (item.Price * number);
ressources.First(x => x.currency == item.Currency).amount -= totalPrice;
DailyReportHandler.GetAndFillTodayReport().moneyForItems += totalPrice;
if (itemsInventory.ContainsKey(item.AssetName))
{
for (int i = 0; i < number; i++)
{
itemsInventory.FirstOrDefault(x => x.Key == item.AssetName).Value.Add(GenerateNewItem(item));
}
}
else
{
itemsInventory.Add(item.AssetName, new List<Item>());
for (int i = 0; i < number; i++)
{
itemsInventory.FirstOrDefault(x => x.Key == item.AssetName).Value.Add(GenerateNewItem(item));
}
}
}
if (ressource != null)
{
int totalPrice = (ressource.price * number);
ressources.First(x => x.currency == Currency.credit).amount -= totalPrice;
DailyReportHandler.GetAndFillTodayReport().moneyForItems += totalPrice;
GameManagerSingleton.Instance.PlayerData.AddResource(ressource.currency, number);
}
}
With GenerateNewItem(item)
like this:
public Item GenerateNewItem(Item item)
{
var newItem = new Item
{
AssetName = item.AssetName,
Currency = item.Currency,
DescriptionLocalizationKey = item.AssetName,
isEquiped = false,
itemType = item.itemType,
NameLocalizationKey = item.NameLocalizationKey,
Price = item.Price,
ShortDescriptionLocalizationKey = item.ShortDescriptionLocalizationKey,
StatAffectedName = item.StatAffectedName,
StatAffectedValue = item.StatAffectedValue
};
return newItem;
}
Upvotes: 0
Reputation: 23
When I create the player, I create the Dictionary like this:
itemsInventory = new Dictionary<string, List<Item>>(),
And when I create the list it's like this:
Instance.PlayerData.itemsInventory.Add("weapon", new List<Item>());
Instance.PlayerData.itemsInventory.Add("armour", new List<Item>());
Instance.PlayerData.itemsInventory.Add("shield", new List<Item>());
Upvotes: 0
Reputation: 35105
From the comment you made "If I update in the debugger it change all items as well." it seems that the values in the list are the same object. This strongly suggests that Item
is a class
(not a struct
).
You need to clone the objects before adding them to the list if they represent different instances.
From Reference types (C# Reference):
With reference types, two variables can reference the same object; therefore, operations on one variable can affect the object referenced by the other variable.
For completeness, you could use a value type (maybe something like record struct
available from C#10):
With value types, each variable has its own copy of the data, and it is not possible for operations on one variable to affect the other (except in the case of in, ref and out parameter variables; see in, ref and out parameter modifier).
Upvotes: 2
Reputation: 23
After I changed from false to true not only the item at index 0 but all objects changes.
Upvotes: 0
Reputation: 151
Use linq to query out the list you want to update and then update the item of the list individually. Use this as an example: How to update a single item of liist of objects using LINQ in C#
Upvotes: 0