Press "Enter" to skip to content

Lesson 10.2: Grouping GameItems in Inventories

Inventories currently hold one object for each GameItem.

We need to do this because we will eventually have effects that are unique for each GameItem – such as enchanting a weapon. However, there are some GameItems that will never have special effects – like snakeskins.

We’re going to make changes to allow us to distinguish between unique items and non-unique items. This will let us have fewer lines in our Inventory datagrids.

Step 1: Modify Engine\Models\GameItem.cs

Add the Boolean “IsUnique” property to the GameItem class.

Add a parameter to the constructor, to let us pass in a Boolean value for the IsUnique property. The “= false” is the default value for this parameter. If we call the constructor without passing in this parameter, it will use a value of “false”.

You can only setup default values for parameters at the end of the parameter list. If you had a default value for a parameter in the middle of the parameter list, the compiler might not know which parameter is missing.

In the Clone function, on line 20, we want to pass the current object’s IsUnique value into its clone.

GameItem.cs
namespace Engine.Models
{
    public class GameItem
    {
        public int ItemTypeID { get; set; }
        public string Name { get; set; }
        public int Price { get; set; }
        public bool IsUnique { get; set; }

        public GameItem(int itemTypeID, string name, int price, bool isUnique = false)
        {
            ItemTypeID = itemTypeID;
            Name = name;
            Price = price;
            IsUnique = isUnique;
        }

        public GameItem Clone()
        {
            return new GameItem(ItemTypeID, Name, Price, IsUnique);
        }
    }
}

Step 2: Modify Engine\Models\Weapon.cs

In the Weapon constructor, where we call the base class constructor (GameItem), pass “true” for the “isUnique” parameter.

This is because we want all weapons to be unique. Weapons will eventually be able to have enchantments, and maybe wear out from use. So, two “pointy sticks” could be different from each other.

Weapon.cs
namespace Engine.Models
{
    public class Weapon : GameItem
    {
        public int MinimumDamage { get; set; }
        public int MaximumDamage { get; set; }

        public Weapon(int itemTypeID, string name, int price, int minDamage, int maxDamage)
            : base(itemTypeID, name, price, true)
        {
            MinimumDamage = minDamage;
            MaximumDamage = maxDamage;
        }

        public new Weapon Clone()
        {
            return new Weapon(ItemTypeID, Name, Price, MinimumDamage, MaximumDamage);
        }
    }
}

Step 3: Create the new class Engine\Models\GroupedInventoryItem.cs

This class holds a GameItem object and a Quantity. It’s like ItemQuantity, except it holds a complete GameItem – instead of only the GameItem’s ID. This is because we need some of the GameItem’s properties (Name and Price), to display in the UI.

GroupedInventoryItem needs to inherit from BaseNotificationClass, so we can raise a property changed event when the Quantity increases or decreases.

GroupedInventoryItem.cs
namespace Engine.Models
{
    public class GroupedInventoryItem : BaseNotificationClass
    {
        private GameItem _item;
        private int _quantity;

        public GameItem Item
        {
            get { return _item; }
            set
            {
                _item = value;
                OnPropertyChanged(nameof(Item));
            }
        }

        public int Quantity
        {
            get { return _quantity; }
            set
            {
                _quantity = value;
                OnPropertyChanged(nameof(Quantity));
            }
        }

        public GroupedInventoryItem(GameItem item, int quantity)
        {
            Item = item;
            Quantity = quantity;
        }
    }
}

Step 4: Modify Engine\Models\LivingEntity.cs

On line 56, add the new property GroupedInventory, whose datatype is ObservableCollection.

Initialize that property on line 64 of the constructor.

Change the AddItemToInventory function on line 67. After adding the item to the Inventory, we need to either:

1) add it to GroupedInventory (if it is unique, or not already in GroupedInventory), or

2) increment its Quantity (if it’s already in GroupedInventory).

On line 79, notice that we add new non-unique items with a quantity of zero. That’s because we’re going to increment the quantity by one on line 82.

Change the RemoveItemFromInventory function on line 88.

On line 92, we get the first GroupedInventoryItem from the GroupedInventory property. If that value is not null (it should never be null, but it’s good to check), we’ll either:

1) completely remove the GroupedInventoryItem from GroupedInventory if its quantity is one (which it will always be for unique items, and could possibly be for non-unique items), or

2) decrease its quantity by one on line 103

We might make more changes in the future, so there is only one property for the inventory. But, this is how we will make the changes now.

LivingEntity.cs
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;

namespace Engine.Models
{
    public abstract class LivingEntity : BaseNotificationClass
    {
        private string _name;
        private int _currentHitPoints;
        private int _maximumHitPoints;
        private int _gold;

        public string Name
        {
            get { return _name; }
            set
            {
                _name = value;
                OnPropertyChanged(nameof(Name));
            }
        }

        public int CurrentHitPoints
        {
            get { return _currentHitPoints; }
            set
            {
                _currentHitPoints = value;
                OnPropertyChanged(nameof(CurrentHitPoints));
            }
        }

        public int MaximumHitPoints
        {
            get { return _maximumHitPoints; }
            set
            {
                _maximumHitPoints = value;
                OnPropertyChanged(nameof(MaximumHitPoints));
            }
        }

        public int Gold
        {
            get { return _gold; }
            set
            {
                _gold = value;
                OnPropertyChanged(nameof(Gold));
            }
        }

        public ObservableCollection<GameItem> Inventory { get; set; }

        public ObservableCollection<GroupedInventoryItem> GroupedInventory { get; set; }

        public List<GameItem> Weapons =>
            Inventory.Where(i => i is Weapon).ToList();

        protected LivingEntity()
        {
            Inventory = new ObservableCollection<GameItem>();
            GroupedInventory = new ObservableCollection<GroupedInventoryItem>();
        }

        public void AddItemToInventory(GameItem item)
        {
            Inventory.Add(item);

            if(item.IsUnique)
            {
                GroupedInventory.Add(new GroupedInventoryItem(item, 1));
            }
            else
            {
                if(!GroupedInventory.Any(gi => gi.Item.ItemTypeID == item.ItemTypeID))
                {
                    GroupedInventory.Add(new GroupedInventoryItem(item, 0));
                }

                GroupedInventory.First(gi => gi.Item.ItemTypeID == item.ItemTypeID).Quantity++;
            }

            OnPropertyChanged(nameof(Weapons));
        }

        public void RemoveItemFromInventory(GameItem item)
        {
            Inventory.Remove(item);

            GroupedInventoryItem groupedInventoryItemToRemove =
                GroupedInventory.FirstOrDefault(gi => gi.Item == item);

            if(groupedInventoryItemToRemove != null)
            {
                if(groupedInventoryItemToRemove.Quantity == 1)
                {
                    GroupedInventory.Remove(groupedInventoryItemToRemove);
                }
                else
                {
                    groupedInventoryItemToRemove.Quantity--;
                }
            }

            OnPropertyChanged(nameof(Weapons));
        }
    }
}

Step 5: Modify WPFUI\MainWindow.xaml

Now we need to change the UI datagrid to use the new GroupedInventory properties.

On line 168, change the DataGrid’s ItemSource to “CurrentPlayer.GroupedInventory”.

Change the Paths for the DataGridTextColumns (lines 173 and 180) to include “Item.”, because GroupedInventory holds a complete GameItem object as its “Item” property, and we want to display the “Name” or “Price” property from “Item”.

I also added a new DataGridTextColumn on 175-178, to display the Quantity value.

MainWindow.xaml
<Window x:Class="WPFUI.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:viewModels="clr-namespace:Engine.ViewModels;assembly=Engine"
        d:DataContext="{d:DesignInstance viewModels:GameSession}"
        mc:Ignorable="d"
        FontSize="11pt"
        Title="Scott's Awesome Game" Height="768" Width="1024">

    <Window.Resources>
        <BooleanToVisibilityConverter x:Key="BooleanToVisibility" />
    </Window.Resources>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="225"/>
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="250"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <!-- Menu -->
        <Label Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Content="Menu" Background="AliceBlue"/>

        <!-- Player stats -->
        <Grid Grid.Row="1" Grid.Column="0" Background="Aquamarine">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>

            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>

            <Label Grid.Row="0" Grid.Column="0" Content="Name:"/>
            <Label Grid.Row="0" Grid.Column="1" Content="{Binding CurrentPlayer.Name}"/>
            <Label Grid.Row="1" Grid.Column="0" Content="Class:"/>
            <Label Grid.Row="1" Grid.Column="1" Content="{Binding CurrentPlayer.CharacterClass}"/>
            <Label Grid.Row="2" Grid.Column="0" Content="Hit points:"/>
            <Label Grid.Row="2" Grid.Column="1" Content="{Binding CurrentPlayer.CurrentHitPoints}"/>
            <Label Grid.Row="3" Grid.Column="0" Content="Gold:"/>
            <Label Grid.Row="3" Grid.Column="1" Content="{Binding CurrentPlayer.Gold}"/>
            <Label Grid.Row="4" Grid.Column="0" Content="XP:"/>
            <Label Grid.Row="4" Grid.Column="1" Content="{Binding CurrentPlayer.ExperiencePoints}"/>
            <Label Grid.Row="5" Grid.Column="0" Content="Level:"/>
            <Label Grid.Row="5" Grid.Column="1" Content="{Binding CurrentPlayer.Level}"/>
        </Grid>

        <!-- Gameplay -->
        <Grid Grid.Row="1" Grid.Column="1"
              Background="Beige">
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>

            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="3*"/>
                <ColumnDefinition Width="2*"/>
            </Grid.ColumnDefinitions>

            <!-- Game Messages -->
            <Border Grid.Row="0" Grid.Column="0"
                    Grid.RowSpan="2"
                    BorderBrush="Gainsboro"
                    BorderThickness="1">

                <RichTextBox x:Name="GameMessages"
                             Background="Beige"
                             VerticalScrollBarVisibility="Auto">
                    <RichTextBox.Resources>
                        <Style TargetType="{x:Type Paragraph}">
                            <Setter Property="Margin" Value="0"/>
                        </Style>
                    </RichTextBox.Resources>
                </RichTextBox>

            </Border>

            <!-- Location information -->
            <Border Grid.Row="0" Grid.Column="1"
                    BorderBrush="Gainsboro"
                    BorderThickness="1">

                <Grid Margin="3">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="*"/>
                        <RowDefinition Height="Auto"/>
                    </Grid.RowDefinitions>

                    <TextBlock Grid.Row="0"
                               HorizontalAlignment="Center"
                               Text="{Binding CurrentLocation.Name}"/>

                    <Image Grid.Row="1"
                           HorizontalAlignment="Center"
                           VerticalAlignment="Center"
                           Height="125"
                           Width="125"
                           Source="{Binding CurrentLocation.ImageName}"/>

                    <TextBlock Grid.Row="2"
                               HorizontalAlignment="Center"
                               Text="{Binding CurrentLocation.Description}"
                               TextWrapping="Wrap"/>
                </Grid>

            </Border>

            <!-- Monster information -->
            <Border Grid.Row="1" Grid.Column="1"
                    BorderBrush="Gainsboro"
                    BorderThickness="1">

                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="*" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>

                    <TextBlock Grid.Row="0"
                               HorizontalAlignment="Center"
                               Height="Auto"
                               Text="{Binding CurrentMonster.Name}" />

                    <Image Grid.Row="1"
                           HorizontalAlignment="Center"
                           VerticalAlignment="Center"
                           Height="125"
                           Width="125"
                           Source="{Binding CurrentMonster.ImageName}" />

                    <StackPanel Grid.Row="2"
                                Visibility="{Binding HasMonster, Converter={StaticResource BooleanToVisibility}}"
                                HorizontalAlignment="Center"
                                Orientation="Horizontal">
                        <TextBlock>Current Hit Points:</TextBlock>
                        <TextBlock Text="{Binding CurrentMonster.CurrentHitPoints}" />
                    </StackPanel>

                </Grid>

            </Border>

        </Grid>

        <!-- Inventory and Quests -->
        <Grid Grid.Row="2" Grid.Column="0"
              Background="BurlyWood">

            <TabControl>
                <TabItem Header="Inventory">
                    <DataGrid ItemsSource="{Binding CurrentPlayer.GroupedInventory}"
                              AutoGenerateColumns="False"
                              HeadersVisibility="Column">
                        <DataGrid.Columns>
                            <DataGridTextColumn Header="Description"
                                                Binding="{Binding Item.Name}"
                                                Width="*"/>
                            <DataGridTextColumn Header="Qty"
                                                IsReadOnly="True"
                                                Width="Auto"
                                                Binding="{Binding Quantity}"/>
                            <DataGridTextColumn Header="Price"
                                                Binding="{Binding Item.Price}"
                                                Width="Auto"/>
                        </DataGrid.Columns>
                    </DataGrid>
                </TabItem>

                <TabItem Header="Quests">
                    <DataGrid ItemsSource="{Binding CurrentPlayer.Quests}"
                              AutoGenerateColumns="False"
                              HeadersVisibility="Column">
                        <DataGrid.Columns>
                            <DataGridTextColumn Header="Name"
                                                Binding="{Binding PlayerQuest.Name}"
                                                Width="*"/>
                            <DataGridTextColumn Header="Done?"
                                                Binding="{Binding IsCompleted}"
                                                Width="Auto"/>
                        </DataGrid.Columns>
                    </DataGrid>
                </TabItem>
            </TabControl>
        </Grid>

        <!-- Action controls -->
        <Grid Grid.Row="2" Grid.Column="1"
              Background="Lavender">

            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>

            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="255" />
            </Grid.ColumnDefinitions>

            <!-- Combat Controls -->
            <Grid Grid.Row="0" Grid.Column="0"
                  Visibility="{Binding HasMonster, Converter={StaticResource BooleanToVisibility}}"
                  HorizontalAlignment="Center"
                  VerticalAlignment="Center">
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>

                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="150"/>
                    <ColumnDefinition Width="10"/>
                    <ColumnDefinition Width="50"/>
                </Grid.ColumnDefinitions>

                <ComboBox Grid.Row="0" Grid.Column="0"
                          ItemsSource="{Binding CurrentPlayer.Weapons}"
                          SelectedItem="{Binding CurrentWeapon}"
                          DisplayMemberPath="Name"
                          SelectedValuePath="ID"/>

                <Button Grid.Row="0" Grid.Column="2"
                        Content="Use"
                        Click="OnClick_AttackMonster"/>
            </Grid>

            <!-- Movement Controls -->
            <Grid Grid.Row="0" Grid.Column="1">

                <Grid.RowDefinitions>
                    <RowDefinition Height="*" />
                    <RowDefinition Height="*" />
                    <RowDefinition Height="*" />
                </Grid.RowDefinitions>

                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>

                <Button Grid.Row="0" Grid.Column="1"
                        Height="25" Width="65" Margin="10"
                        Click="OnClick_MoveNorth"
                        Visibility="{Binding HasLocationToNorth, Converter={StaticResource BooleanToVisibility}}"
                        Content="North"/>
                <Button Grid.Row="1" Grid.Column="0"
                        Height="25" Width="65" Margin="10"
                        Click="OnClick_MoveWest"
                        Visibility="{Binding HasLocationToWest, Converter={StaticResource BooleanToVisibility}}"
                        Content="West"/>
                <Button Grid.Row="1" Grid.Column="1"
                        Height="25" Width="65" Margin="10"
                        Click="OnClick_DisplayTradeScreen"
                        Visibility="{Binding HasTrader, Converter={StaticResource BooleanToVisibility}}"
                        Content="Trade"/>
                <Button Grid.Row="1" Grid.Column="2"
                        Height="25" Width="65" Margin="10"
                        Click="OnClick_MoveEast"
                        Visibility="{Binding HasLocationToEast, Converter={StaticResource BooleanToVisibility}}"
                        Content="East"/>
                <Button Grid.Row="2" Grid.Column="1"
                        Height="25" Width="65" Margin="10"
                        Click="OnClick_MoveSouth"
                        Visibility="{Binding HasLocationToSouth, Converter={StaticResource BooleanToVisibility}}"
                        Content="South"/>

            </Grid>

        </Grid>

    </Grid>
</Window>

Step 6: Modify WPFUI\TradeScreen.xaml and TradeScreen.xaml.cs

We also need to update the inventory datagrids on the trading screen. These are the same changes as we made for MainWindow.

Lines 40 and 71 need to use GroupedInventory, instead of Inventory.

Lines 51, 59, 86, and 94 need to have “Item.” Added to the property paths.

Add new DataGridTextColumns for the Quantity on lines 52-55 and 87-90.

Finally, change the button text to include “1”, so the player knows they are selling or buying one of the item, and not the total quantity of that item. The button changes are on lines 65 and 100.

In TradeScreen.xaml.cs, we need to change the buy and sell functions, because the datagrids now contain GroupedInventoryItem objects, instead of ItemQuantity objects.

In OnClick_Sell and OnClick_Buy, we need to cast the event sender to a GroupedInventoryItem object. Then, change the buying and selling code to use groupedInventoryItem.Item.Price and groupedInventoryItem.Item.

TradeScreen.xaml
<Window x:Class="WPFUI.TradeScreen"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:viewModels="clr-namespace:Engine.ViewModels;assembly=Engine"
        d:DataContext="{d:DesignInstance viewModels:GameSession}"
        mc:Ignorable="d"
        WindowStartupLocation="CenterOwner"
        FontSize="11pt"
        Title="Trade Screen" Height="480" Width="640">

    <Grid Margin="10">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <Label Grid.Row="0" Grid.Column="0"
               Grid.ColumnSpan="2"
               HorizontalAlignment="Center"
               Content="{Binding CurrentTrader.Name}"/>

        <Label Grid.Row="1" Grid.Column="0"
               HorizontalAlignment="Center"
               Content="Your Inventory"/>
        <Label Grid.Row="1" Grid.Column="1"
               HorizontalAlignment="Center"
               Content="Trader's Inventory"/>

        <DataGrid Grid.Row="2" Grid.Column="0"
                  Margin="10"
                  ItemsSource="{Binding CurrentPlayer.GroupedInventory}"
                  AutoGenerateColumns="False"
                  HeadersVisibility="Column"
                  CanUserAddRows="False"
                  CanUserDeleteRows="False"
                  VerticalScrollBarVisibility="Auto">

            <DataGrid.Columns>
                <DataGridTextColumn Header="Description"
                                    IsReadOnly="True"
                                    Width="*"
                                    Binding="{Binding Item.Name}"/>
                <DataGridTextColumn Header="Qty"
                                    IsReadOnly="True"
                                    Width="Auto"
                                    Binding="{Binding Quantity}"/>
                <DataGridTextColumn Header="Price"
                                    IsReadOnly="True"
                                    Width="Auto"
                                    Binding="{Binding Item.Price}"/>
                <DataGridTemplateColumn MinWidth="75">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Button Click="OnClick_Sell"
                                    Width="55"
                                    Content="Sell 1"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>

        </DataGrid>

        <DataGrid Grid.Row="2" Grid.Column="1"
                  Margin="10"
                  ItemsSource="{Binding CurrentTrader.GroupedInventory}"
                  AutoGenerateColumns="False"
                  HeadersVisibility="Column"
                  CanUserAddRows="False"
                  CanUserDeleteRows="False"
                  VerticalScrollBarVisibility="Auto">

            <DataGrid.Columns>
                <DataGridTextColumn Header="Description"
                                    IsReadOnly="True"
                                    Width="*"
                                    Binding="{Binding Item.Name}"/>
                <DataGridTextColumn Header="Qty"
                                    IsReadOnly="True"
                                    Width="Auto"
                                    Binding="{Binding Quantity}"/>
                <DataGridTextColumn Header="Price"
                                    IsReadOnly="True"
                                    Width="Auto"
                                    Binding="{Binding Item.Price}"/>
                <DataGridTemplateColumn MinWidth="75">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Button Click="OnClick_Buy"
                                    Width="55"
                                    Content="Buy 1"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>

        </DataGrid>

        <Button Grid.Row="3" Grid.Column="1"
                HorizontalAlignment="Right"
                Width="75"
                Content="Close"
                Click="OnClick_Close"/>
    </Grid>
</Window>
TradeScreen.xaml.cs
using System.Windows;
using Engine.Models;
using Engine.ViewModels;

namespace WPFUI
{
    /// <summary>
    /// Interaction logic for TradeScreen.xaml
    /// </summary>
    public partial class TradeScreen : Window
    {
        public GameSession Session => DataContext as GameSession;

        public TradeScreen()
        {
            InitializeComponent();
        }

        private void OnClick_Sell(object sender, RoutedEventArgs e)
        {
            GroupedInventoryItem groupedInventoryItem =
                ((FrameworkElement)sender).DataContext as GroupedInventoryItem;

            if(groupedInventoryItem != null)
            {
                Session.CurrentPlayer.Gold += groupedInventoryItem.Item.Price;
                Session.CurrentTrader.AddItemToInventory(groupedInventoryItem.Item);
                Session.CurrentPlayer.RemoveItemFromInventory(groupedInventoryItem.Item);
            }
        }

        private void OnClick_Buy(object sender, RoutedEventArgs e)
        {
            GroupedInventoryItem groupedInventoryItem =
                ((FrameworkElement)sender).DataContext as GroupedInventoryItem;

            if(groupedInventoryItem != null)
            {
                if(Session.CurrentPlayer.Gold >= groupedInventoryItem.Item.Price)
                {
                    Session.CurrentPlayer.Gold -= groupedInventoryItem.Item.Price;
                    Session.CurrentTrader.RemoveItemFromInventory(groupedInventoryItem.Item);
                    Session.CurrentPlayer.AddItemToInventory(groupedInventoryItem.Item);
                }
                else
                {
                    MessageBox.Show("You do not have enough gold");
                }
            }
        }

        private void OnClick_Close(object sender, RoutedEventArgs e)
        {
            Close();
        }
    }
}

Step 7: Test the game

Fight some monsters, collect loot items, and visit the trader. make sure there are multiple lines for weapons, and only one line for each non-unique item (like snakeskins).

Leave a Reply

Your email address will not be published. Required fields are marked *