RPG Item Statistics

I have 100 items. Each item has its own specific values (like strength, armor,attack). These values are never changed and all hard coded. What is the best way to organize and access these 100 items in c#? I was thinking about a struct, but creating a struct constructor that has 10+ parameters didn’t seem too logical.

The player will find these items and can choose to add the item to the inventory. When that happens I want to be able to add that struct/whatever to the players inventory list. Any ideas on how to best approach this?

I also was thinking about creating a class for the item, and then storing the class instances into a list, but I don’t know how fill each instance with pre-determined data.

A good comparison is Diablo II. The game has many items that each hold a series of values (+ 15% luck, + 15 strength, etc.)

There are like a billion ways to approach this issue. First you will want to probably store your items in some database so you can update/change them when ever you need for the game, even if it is in a file on the file system, I wouldn’t statically store them in code especially because you might find you need to adjust the stats to make the game more challenging or easier, etc.

Otherwise, you could do something like the following (stripped down from one of my projects)

internal class GameItems
    {
        internal List<Armor> armor;
        internal List<Weapon> weapon;

        internal void GameItems()
        {
            armor = new List<Armor>();
            weapon = new List<Weapon>();
        }


        internal void AddNewArmor()
        {
            using (Armor _armor = new Armor())
            {
                // Give this new armor a unique ID
                _armor.ID = new Guid().ToString();

                // update the attributes
                _armor.Name = "New Armor";

                armor.Add(_armor);
            }
        }

        internal void AddNewWeapon()
        {
            using (Weapon _weapon = new Weapon())
            {
                // Give this new weapon a unique ID
                _weapon.ID = new Guid().ToString();

                // update the attributes
                _weapon.Name = "New Weapon";

                weapon.Add(_weapon);
            }
        }
    }

    class Armor : Attributes
    {
        void Armor()
        {
            
        }
    }

    class Weapon : Attributes
    {
        void Weapon()
        {
            
        }
    }

    class Attributes : Statistics
    {
        internal string ID;
        internal string Name;
        internal bool Stackable;
        internal int Quantity;
        internal int Race;
    }

    class Statistics : Elemental
    {
        internal int HitPoints;
        internal int Value;
        internal int Bonus;
        internal int AbsorbDamage;
        internal int DamageAmount;
    }

    class Elemental : IDisposable
    {
        enum type
        {
            Earth, Wind, Fire, Water, Ethereal, Light, Dark
        }
        internal int DamageBonus;
        internal int ArmorBonus;
        internal type Type;
    }

Now, you populate your list with game objects based on types somewhere in code reading from some external source for dynamic build or have a static build internally to fill that list. shrugs, even diablo has an items file.

I think I understand whats going on here. Do you have any recommendations on type of datafile I should use to put the item information in, and how to get the right data into the right spot?

In the past i have used streamreader to read from a txt file and read each line into a list/dictionary, but in this case i’m not sure how to format the txt file and read it in appropriately.

myItems.txt

FireSword
25
18
6
IceSword

So lets say that each weapon in my class had 4 attributes, name, damage,defense,elemental damage,
How might i read those values and send them to the appropriate places in your example?

Well, depends on if you want the file to be human readable or not. You can save it as an XML document or a binary file, you can serialize the class structure and simply save a serialized version of the item list, then you can read it back in and deserialize it, would probably be the fastest way.

I could probably throw an example code block together in a few hours if you haven’t figured it out by then.

Haha, i wouldn’t complain for some code. I’m Still workin on it! :slight_smile:

Although I did this quick project in Visual Studio 2010, you can take the c# files and put them in 2008 or 2005 if you like, anyway, what is in here, is a form that takes the 4 values you want to store, allows you to add them to a list, shows you the list in a textbox (too lazy to do a datagrid view), and allows you to save them to a binary file, or load them from a binary file. There is the windows forms code to see how it works and the class file independent of the windows form that is the class needed to do the serialization.

What I will also do, is here in this thread post the code for the form (minus the form components) and the code for the serialization class.

FORM CODE

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using Inventory;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace RPGExample
{
    public partial class frmInventory : Form
    {

        List<GameItems> _GameItems = new List<GameItems>();        

        public frmInventory()
        {
            InitializeComponent();
        }

        private void btnAddItem_Click(object sender, EventArgs e)
        {
            GameItems item = new GameItems();
            item.Name = tbName.Text.ToString();
            item.Damage = Convert.ToInt32(tbDamage.Text);
            item.ElementalDamage = Convert.ToInt32(tbElementalDamage.Text);
            item.Defense = Convert.ToInt32(tbDefense.Text);

            _GameItems.Add(item);

            
            tbData.Text += "Name: " + item.Name + Environment.NewLine;
            tbData.Text += "Damage: " + item.Damage.ToString() + Environment.NewLine;
            tbData.Text += "Defense: " + item.Defense.ToString() + Environment.NewLine;
            tbData.Text += "Elemental Damage: " + item.ElementalDamage.ToString() + Environment.NewLine;
            tbData.Text += Environment.NewLine;
        }

        private void btnLoadItems_Click(object sender, EventArgs e)
        {
            LoadItems();
            tbData.Text = string.Empty;

            foreach (GameItems item in _GameItems)
            {
                tbData.Text += "Name: " + item.Name + Environment.NewLine;
                tbData.Text += "Damage: " + item.Damage.ToString() + Environment.NewLine;
                tbData.Text += "Defense: " + item.Defense.ToString() + Environment.NewLine;
                tbData.Text += "Elemental Damage: " + item.ElementalDamage.ToString() + Environment.NewLine;
                tbData.Text += Environment.NewLine;
            }
        }

        private void frmInventory_Load(object sender, EventArgs e)
        {
            LoadItems();
        }

        private void btnSaveItems_Click(object sender, EventArgs e)
        {
            SaveItems();
        }

        private void SaveItems()
        {
            Stream stream = File.Open("GameInfo.inf", FileMode.Create);
            BinaryFormatter bformatter = new BinaryFormatter();
            bformatter.Serialize(stream, _GameItems);
            stream.Close();
        }

        private void LoadItems()
        {
            if (File.Exists("GameInfo.inf"))
            {
                _GameItems.Clear();
                Stream stream = File.Open("GameInfo.inf", FileMode.Open);
                BinaryFormatter bformatter = new BinaryFormatter();
                _GameItems = (List<GameItems>)bformatter.Deserialize(stream);
                stream.Close();
            }
        }
    }
}

SERIALIZATION OBJECT CODE

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace Inventory
{
    [Serializable()]
    public class GameItems : ISerializable
    {
        public string ID;
        public string Name;
        public int Damage;
        public int Defense;
        public int ElementalDamage;

        public GameItems()
        {
            ID = new Guid().ToString();
            Name = string.Empty;
            Damage = 0;
            Defense = 0;
            ElementalDamage = 0;
        }

        // Deserialization
        public GameItems(SerializationInfo info, StreamingContext ctxt)
        {
            ID = (String)info.GetValue("ID", typeof(string));
            Name = (String)info.GetValue("Name", typeof(string));
            Damage = (int)info.GetValue("Damage", typeof(int));
            Defense = (int)info.GetValue("Defense", typeof(int));
            ElementalDamage = (int)info.GetValue("ElementalDamage", typeof(int));
        }

        // Serialization
        public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
        {
            info.AddValue("ID", ID);
            info.AddValue("Name", Name);
            info.AddValue("Damage", Damage);
            info.AddValue("Defense", Defense);
            info.AddValue("ElementalDamage", ElementalDamage);
        }
    }
}

355417–12355–$rpgexample_655.zip (64.6 KB)

DOH I forgot to turn on the scrollbars for the textbox, that is simple enough, just set it to “Both” and rebuild the project, otherwise just click in the textbox with the list of items and juse the arrow key to scroll through if you add to it to see the new item, call me lazy. Oh yea, this was just quick and dirty so there is no code to check the values to see if you actually used a number in the values that require a number, that is the damage, defense, and elemental damage fields. You can do all that, this is purely an example based on your request.