[C++] Link errors

Status
Not open for further replies.
In terms of grouping items for vectors, it's entirely up to you. There are advantages to doing things either way, but you may be right that it would be easier to keep track of items in vectors rather than their properties. You could, for instance, create
Code:
vector<Item> inventory

You could also have an Item class that other classes inherit from to create
Code:
vector<Weapon> weaponInventory

If you use inheritance, you could have basic item properties within the Item class and then have special item properties for the classes that inherit from the main class.


Given the small size of the XML file, I would suggest using your own method or looking at http://msdn.microsoft.com/en-us/library/ekw4dh3f(v=vs.71).aspx
I don't imagine you are wanting to create a true dataset, but that organization scheme may give you ideas.


If you want to vary the number of items in a chest, it would probably be easier to create a constructor that takes in an array or vector so you can vary the size of what is input rather than varying the number of variables the constructor takes in.
 
Thanks Mike - I've started creating an XML file. The constructor taking a vector is a good idea - forgot that was an option.
 
I've gone back to this after a break. Spent the past few hours working out various bits of code for it, still implementing the XML inventory file.

I've written this function - it's very clumsy, and doesn't work properly. (Does not store the correct values, also is very slow and eventually results in a range error.)

Code:
vector<Item> load_items(string filename)
{
	//Load items into vector<Items>
	vector<string> raw_items;
	vector<Item> items;
	int startline = 3; //Ignores first 3 lines.
	int endlines = 1; //Ignores final line

	raw_items = read_file(filename);
	size_t end = raw_items.size() - endlines;

	for(int i = startline; i < end; i++)
	{
		//Parses XML file into Item data.
		i++;
		Item temp;
		string s;

		s = strip_tag(raw_items[i]); 
		temp.id = string_to_float(s);
		i++;

		s = strip_tag(raw_items[i]); 
		temp.name = s;
		i++;

		s = strip_tag(raw_items[i]);
		temp.value = string_to_float(s);
		i++;

		s = strip_tag(raw_items[i]);
		temp.quest = string_to_bool(s);
		i++;

		s = strip_tag(raw_items[i]);
		temp.food = string_to_bool(s);
		i++;

		s = strip_tag(raw_items[i]);
		temp.restorehp = string_to_float(s);
		i++;

		s = strip_tag(raw_items[i]);
		temp.equip = string_to_bool(s);
		i++;

		s = strip_tag(raw_items[i]);
		temp.armour = string_to_float(s);
		i++;

		s = strip_tag(raw_items[i]);
		temp.attack = string_to_float(s);
		i++;

		s = strip_tag(raw_items[i]);
		temp.speed = string_to_float(s);
		i++;

		items.push_back(temp);
		i++;

	}

	return items;
}

An Item object is:

Code:
class Item{
	//Contains a single item.

public:
	float id; //unique item ID
	string name; //item name, as displayed to player	
	float value; //economic value of item
	bool quest; //quest item?
	bool food; //food item?
	float restorehp; //value of health restored
	bool equip; //Can item be equiped?
	float armour; //item armour rating
	float attack; //item damage rating
	float speed; //item speed rating

	
};

My XML file looks like:

Code:
<?xml version="1.0" encoding="utf-8"?>

<Items_Table>
  <item>
    <item_id>1</item_id>
    <item_name>Wooden Spoon</item_name>
    <item_value>1</item_value>
    <item_quest>false</item_quest>
    <item_food>false</item_food>
    <item_restorehp>0</item_restorehp>
    <item_equip>true</item_equip>
    <item_armour>0</item_armour>
    <item_attack>1</item_attack>
    <item_speed>5</item_speed>
  </item>
</Items_Table>

I want to load all items from the XML database, into a vector of Item objects. I'm sure there is a much better method for doing this than my function above - just not sure how. Does anyone have any ideas for a more effective method?
 
I've worked out a solution. I've re-written the load_items function. Everything is now working as intended.

Code:
vector<Item> load_items(string filename)
{
	//Load items into vector<Items>
	vector<string> raw_items;
	vector<string> new_items;
	vector<Item> items;
	int startline = 3; //Ignores first 3 lines.
	int endlines = 1; //Ignores final line

	raw_items = read_file(filename);
	size_t end = raw_items.size();
	Item temp;
	string s;

	for(int i = 0; i< end; i++)
	{
		string s = raw_items[i];
		size_t start = s.find(">");
		size_t end = s.find("</");
		size_t check = s.size();

		if(start < end &&  end < check)
		{
			s = strip_tag(s);
			new_items.push_back(s);
		}

	}

	for(int i = 0; i < new_items.size(); i++)
	{
		s = new_items[i]; 
		temp.id = string_to_float(s);
		i++;

		s = new_items[i];  
		temp.name = s;
		i++;

		s = new_items[i]; 
		temp.value = string_to_float(s);
		i++;

		s = new_items[i]; 
		temp.quest = string_to_bool(s);
		i++;

		s = new_items[i]; 
		temp.food = string_to_bool(s);
		i++;

		s = new_items[i];  
		temp.restorehp = string_to_float(s);
		i++;

		s = new_items[i];  
		temp.equip = string_to_bool(s);
		i++;

		s = new_items[i];  
		temp.armour = string_to_float(s);
		i++;

		s = new_items[i]; 
		temp.attack = string_to_float(s);
		i++;

		s = new_items[i];  
		temp.speed = string_to_float(s);

		items.push_back(temp);
	}

	return items;
}
 
Was going to look into this tonight, but I am happy to see you fixed it on your own. Nice work!
 
Thanks Mike, I appreciate you looking. I'm glad I was able to remember enough after leaving it for a while.

As always, a new question... I have the following class defined in a header file:

Code:
//Base inventory.
class Inventory
{	
public:
	Inventory(vector<Item> &v_items);
	bool check(float id);
	bool add(float id);
	bool remove(float id);


private:
	vector<Item> c_items;
	vector<Item> pack;
};

In the source file - will this work as a constructor?

Code:
Inventory::Inventory(vector<Item> &v_items)
	:items(&v_items) { }

I want all inventory objects to have access to the item list, loaded in the load_items function I managed to fix above. I want to use the variable c_items within the class code, whenever I need to look up an item. Does that constructor work? Not sure if I can assign a vector like that.
 
Not sure what :items(&v_items) does at the end of that constructor definition you have. Are you trying to inherit from another class?
 
It's a way of setting up values in the constructor - I'm not sure if it works that way for a Vector though. I've copied the code from the Attribute system:

//Attribute structure
Attribute::Attribute()
:name(), points() { }
Attribute::Attribute(string n)
:name(n), points(0) { }
Attribute::Attribute(string n, int p)
:name(n), points(p) { }

For the last one, string name is set as n, and int points is set as p.

I'm trying to do the same with the vector. The items are loaded into a vector at the start of the game - instead of copying the vector multiple times, I want every class that requires access to the item list to have a local variable - items - which is a reference to the original item vector. I'm trying to assign in the constructor.

vector<Item> items = vector<Item> &v_items

Hopefully my intention is making sense - it's 2am here. :lol:
 
Not sure if that works. I've never assigned a function a value like that. Maybe someone with more experience with c++ has?

Referring to my c++ manual now...

Ah okay, I think I found it. Where do you define what type of variable items is?
 
Alright, I have created a very simple project that shows how to do what you are trying to do.
 
Thanks Mike, that's very kind.

I'm using Bjarne Stroustrup's course book - Programming, Principles and Practice. That's the first constructor method that's been shown so far.

Thanks again for the code - I'll take a look shortly and see if I can get any further.
 
No problem. I have quite a bit of c++ programming experience, but I have never done data assignments before the constructor is executed before. I think I missed that option when I was learning; my book explains that it can be helpful in some situations and should be used when initializing data types as you are, but most of the time, constructor behavior requires more complicated tasks be performed which have to be done within the constructor body.
 
Finally managed to look over the code - that method works fine for me. Is there a way to use only one vector though rather than copying it multiple times? This constructor code is likely to be called several times as it's going to be the basis for several classes - I'd like to have one loaded vector that all inventories are able to reference, rather than several copies of it.

It won't make any difference to the program itself, but I'd like to know how to do it both ways.
 
I usually build my classes in a hierarchical way, so any class that is going to be accessed by many classes is first created as an object by a lower level class. That lower level class is then used to create an object that the other classes use, and that way, all classes will have access to the object needed by each class. You will need to organize the architecture of your code in such a way that there is a base class/object that all other classes/objects can interface with through each other.

I don't know if that makes sense to you; let me know if you have questions. I can try to put together an example to help you understand what I mean.
 
It makes sense - not sure how to actually do it though. Would this be done through inheritance, or a different method I'm unfamiliar with?

If the vector is created in the base inventory class - would child classes have direct access to that vector, or to only a copy? Oh... but constructors aren't inherited... sorry, I'm already scraping the boundaries of my limited C++ knowledge with this project as it is.

As always I appreciate your help, I know how busy you are.
 
Just wanted you to know I hadn't forgotten about this. I did find an example, but I am not sure how much use it can be. What would help is knowing what classes you plan on designing and how they are going to use the inventory list.

Do you know how to put together a Unified Modeling Language (UML) class diagram?

Does your c++ book have information on Software Development organization? It may be one of the last chapters of the book.
 
It doesn't have a specific chapter as far as I can see on organization - it may be covered in the book though. Last chapters are on unit tests and C, so probably. I'm using Visual Studio 2012 - does it have any UML tools with it? If not, any recommendations for a program?

I'm trying to write it as modular as possible, but I maybe haven't thought far enough ahead to give a full plan, but the inventory system is as follows:

Base class - Inventory. Contains a vector of Item objects + add/remove functions. All inventory classes are derived from this.
Chest - similar to base Inventory. Lootable chest.
Bank - similar to chest, but permanent. Only one loaded.
Player_Inventory - contains two Item vectors. Pack and Equipped + functions to swap between them. Only one - created at start of game. Always accessible to player.
NPC_Inventory - also two Item vectors, but overall is simpler than Player_Inventory. Created when the NPC/Monster is loaded - once items are in it they don't need to change until the NPC is dead.

I think it's easier for all inventories to work from a vector database of Items, rather than all looking at the XML. Item data is stored in items.xml - basically the vector is only needed as a reference. I want each class to be able to accept the command:

whatever_inventory.add(4)

It'll then look up what item corresponds to the ID (4), and then add the item to the appropriate vector.

Not yet sure how these will interact with the rest of the game - NPC_Inventory will need to be loaded by whatever function creates NPCs, and will also need to be linked to the combat functions. Need to know when the NPC is dead so the inventory is accessible by the player. I'm intending interaction with the game to take place through commands:

/travel
/attack
/talk

etc.
 
If it were me, here is how I would do it:

  1. An item class that has the attributes for each item stored within it; this may require multiple item classes if some items have different attributes. You can load the items into this class from the xml file when the game starts, or you can load them as you play based on what items are needed by each of the other classes. Loading at the start of the game would make the game faster, but the load time would be longer.

  2. An inventory class that then adds items to it based on the item number and xml file (if not loading the xml file at the beginning of the game) or the item number and loaded items list from the xml file that is stored within the items class (if the xml file is loaded at the beginning of the game and stored in memory).

  3. The Chest class that has items chosen by area or random items within it. It would have its own inventory object made up of a vector of items.

  4. The Bank class that has items chosen by area or random items within it. It would have its own inventory object made up of a vector of items.

  5. The Player_Inventory class that has items chosen by area or random items within it. It would have its own inventory object made up of a vector of items.

  6. The NPC_Inventory class that has items chosen by area or random items within it. It would have its own inventory object made up of a vector of items.

  7. An InventoryOrganization class where all the objects are created. This would have the items object created so it can be used by all other objects. Some example code follows:

    Code:
    #ifndef INVENTORYORGANIZATION_H
    #define INVENTORYORGANIZATION_H
    
    #include Item.h
    #include Chest.h
    #include Bank.h
    #include Player_Inventory.h
    #include NPC_Inventory.h
    
    Class InventoryOrganization
    {
    Public:
      // functions
      InventoryOrganization();
      virtual ~InventoryOrganization();
      
      void addChestInventory(Chest* chest, vector<int> index);
      void addBankInventory(Bank* bank, vector<int> index);
      void addPlayerInventory(Player_Inventory* player, vector<int> index);
      void addNPCInventory(NPC_Inventory* NPC, vector<int> index);
      // variables
      Item* invItem;
    Private:
    Protected:
    };
    #endif

    Code:
    // InventoryOrganization.cpp
    
    #include Item.h
    #include Chest.h
    #include Bank.h
    #include Player_Inventory.h
    #include NPC_Inventory.h
    #include InventoryOrganization.h
    
    InventoryOrganization::InventoryOrganization()
    {
      invItem = new Item();
      // Loading the xml file at the beginning of the game, which is what I would do
      //  If the xml file is large, you can load it on a separate thread when the game's
      //  title credits are showing
      invItem->loadXml(); 
    }
    
    InventoryOrganization::~InventoryOrganization()
    {
      delete invItem;
    }
    
    void InventoryOrganization::addChestInventory(Chest* chest, vector<int> index){
      for(int i=0; i<int(index.size()); i++){
        int i1 = index[i];
        chest->add(invItem->items[i1]);
      }
    }
    
    void InventoryOrganization::addBankInventory(Bank* bank, vector<int> index){
      for(int i=0; i<int(index.size()); i++){
        int i1 = index[i];
        bank->add(invItem->items[i1]);
      }
    }
    
    void InventoryOrganization::addPlayerInventory(Player_Inventory* player, vector<int> index){
      for(int i=0; i<int(index.size()); i++){
        int i1 = index[i];
        player->add(invItem->items[i1]);
      }
    }
    
    void InventoryOrganization::addNPCInventory(NPC_Inventory* NPC, vector<int> index){
      for(int i=0; i<int(index.size()); i++){
        int i1 = index[i];
        NPC->add(invItem->items[i1]);
      }
    }


With the above method, you will need to include Item.h in each of the classes that get inventory items, but you will not have to load the xml file for each. The Item class is only included in each other other classes so the classes know the layout of the Item being passed in.

If you have different item classes, you will need to overload functions to pass those in.

Make sense?
 
Last edited:
Just realized there was an error in my code; I have corrected it. Should be easier to follow now. Let me know if you have questions.
 
Hi Mike,

Sort of makes sense - I think I still need to learn a bit more first.

Unfortunately I have another question. :grin1: I have this class:

Code:
//Base inventory.
class Inventory
{	
public:
	Inventory();
	Inventory(vector<Item> v_items);
	bool check(float id);
	bool add(float id);
	bool remove(float id);
	int find(float id);


private:
	vector<Item> items;
	vector<Item> store;
};

items is the list of items, and store is the contents of this particular inventory. If I use this class as a base class for inheritance, will any function that uses "store" fail to work? Would it work if other classes used a private vector with the same name? It struck me as I created the function "find" to return the position of an item in the store vector - I want this function to be accessible to all Inventory classes, but I've realized that it probably won't work through inheritance.
 
Status
Not open for further replies.

Has Sysnative Forums helped you? Please consider donating to help us support the site!

Back
Top