RPG File i/o question

Pages: 12
I have a file that I plan on using for a script I want to create for a console text RPG I have been using to learn C++. I want to create a class to read data from a text file. It will populate items and creatures in the game. I was wondering if there were any thorough and easy to understand tutorials to help me piece through how to read data from a text file to use into variables in a program? Here is an example of my text file:

// Items.txt Begins
// Ignore lines with // proceeding them
// # Starts a new section example: # ARMOR
// @ Ends a section
//
// Weapons will have the following format:
// Item Description Rarity Min_Damage Max_Damage Value(in copper silver or gold)
// Example:
// SSword "Short Sword" common 2 4 copper 5
// LSword "Long Sword" common 4 7 copper 10
// SciSword "Scimitar" uncommon 25 35 silver 2
// DragSword "Dragon Sword" rare 150 200 gold 125
// Excal1 "Excalibur" legand 1000 1300 gold 10000
# Weapons
SSword "Short Sword" common 2 4 copper 5
@
// Armor will have the following format:
// Item Description Rarity Protection Value(in copper silver or gold)
// Example:
// LArmor "Leather Armor" common 1 copper 10
// SiStArmor "Silver Steel Armor" uncommon 40 silver 2
// DArmor "Dragon Armor" rare 110 gold 100
// GArmor "Armor of the Gods" legand gold 10000
# Armor
LArmor "Leather Armor" common 1 copper 10
@
// Consumables will have the following format:
// Item Description Rarity Value(in copper silver or gold) Heal amount Damage amount
// Armor amount time(seconds) StatBoost // amount time(seconds)
// 0 means null(no effect/use) Some headings require yes/true no/false indicated by 1 or 0
// For time 999999 means permanent
// SPotion "Small Potion" common copper 5 1 10 0 0 0 0 0 0 0
// StrPotion "Strength Potion" uncommon silver 3 0 0 0 0 0 0 strength 5 999999
// HerculesSalve "Hercules Salve"legand gold 2000 0 0 0 0 0 0 strength 25 600
# Consumables
SPotion "Small Potion" common copper 5 1 10 0 0 0 0 0 0 0
@
// Items.txt Ends

I would also be willing to accept any ideas. Basically I don't know how to search for text, or use text as data for variables in my program. I do know how to open and read lines in a file, how to create files...the very basics of file i/o.

Edit:
I decided to break up the file for each heading. Here is an example:

//Start Weapons.txt
// Ignore lines with // proceeding them
// Weapons will have the following format:
// Item Description Rarity Min_Damage Max_Damage Value(in copper silver or gold)
// Example:
// SSword "Short Sword" common 2 4 copper 5
// LSword "Long Sword" common 4 7 copper 10
// SciSword "Scimitar" uncommon 25 35 silver 2
// DragSword "Dragon Sword" rare 150 200 gold 125
// Excal1 "Excalibur" legand 1000 1300 gold 10000
SSword "Short Sword" common 2 4 copper 5
//End Weapons.txt
Last edited on
I started a program to test some ideas:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main()
{
    ifstream file; //declare file
    file.open("Weapons.txt");//make weapons.txt file
    //declaring needed variables
    string Item, Description, Rarity, CoinType;
    int MIN_Damage, MAX_Damage, CoinAmount;
    string word;
    //the meat of the program...I hope
    while(!file.eof())//while eof is not reached
    {
        while(word != "/")// '/' declares comment line, I don't want those
        {
            while(file.peek() != '\n')//do this for one valid line at a time
            {
                //putting data in variables one by one
                file >> Item;
                file >> Description;
                file >> Rarity;
                file >> MIN_Damage;
                file >> MAX_Damage;
                file >> CoinType;
                file >> CoinAmount;
            }
        }
    }
    file.close();//close the file explicitly
    //Checking to see if the variables are correctly set
    cout << Item << endl << Description << endl << Rarity << endl;
    cout << MIN_Damage << endl << MAX_Damage << endl;
    cout << CoinType << ": " << CoinAmount << "\n\n";
    return 0;//obviously needed in main()
}


But all I get is a blinking cursor which doesn't allow any user input.
Last edited on
On line 17 you're caught in an infinite loop. There are a few things wrong with this line:
1. word is never set
2. Your checking if the entire string is "/", if there is something after that then the condition will be true.
3. This should be an if statement otherwise we will keep checking without any change.

I would probably do it like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
ifstream file("Weapons.txt"); //this will open the file in a single line.  file.open() is not required.
string Line;
while(!file.eof())//while eof is not reached
{
    getline(file,Line); //Get the whole line

    if (Line[0] == '/') //Use single quotes if evaluating a single character
        continue;        //Skip the stuff below

    stringstream iss;    //Make a stringstream object to spit apart the line
    iss << Line;        //Put our line into the stringstream object

    //putting data in variables one by one
    iss >> Item;
    iss >> Description;
    iss >> Rarity;
    iss >> MIN_Damage;
    iss >> MAX_Damage;
    iss >> CoinType;
    iss >> CoinAmount;
}
Last edited on
I tried your code but it gave me an error. Did I code it wrong?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

iint main()
{
    ifstream file("Weapons.txt"); //this will open the file in a single line.  file.open() is not required.
    //declaring needed variables
    string Item, Description, Rarity, CoinType;
    int MIN_Damage, MAX_Damage, CoinAmount;
    string line;
    stringstream iss;    //Make a stringstream object to spit apart the line
    while(!file.eof())//while eof is not reached
    {
        getline(file,line); //Get the whole line

        if (line[0] == '/') //Use single quotes if evaluating a single character
            continue;        //Skip the stuff below

        iss << line;        //Put our line into the stringstream object

        //putting data in variables one by one
        iss >> Item;
        iss >> Description;
        iss >> Rarity;
        iss >> MIN_Damage;
        iss >> MAX_Damage;
        iss >> CoinType;
        iss >> CoinAmount;

        cout << Item << endl << Description << endl << Rarity << endl;
        cout << MIN_Damage << endl << MAX_Damage << endl;
        cout << CoinType << ": " << CoinAmount << "\n\n";
    }
    file.close();
    return 0;
}


The error is:
F:\CodeBlocks-Programs\FileManip\main.cpp|83|error: aggregate 'std::stringstream iss' has incomplete type and cannot be defined|
Last edited on
#include <sstream>

When you include sstream, you can remove #include <string> , as it's included through #include <sstream>
Thank you, Lynx361. I changed the include and now I have myself an infinite loop. Do you where I wen't astray?
Last edited on
361 is my total posts, not my name! lol (:

I've never used ss like you've done it, before.

I've always done it like:
iss( line );

On another note, you may want to move the brace at line 35, up to line 31?

Get all the information from the file, and then cout it all.
Last edited on
Am I supposed to change line 21 to iss(line);? Also I need to cout the line each time it reads a new line in a file which will have many items listed.
Yeah, try changing line 21 to iss( line );.

I'm guessing that all variables are stored on one line?
Yeah, the whole line is packed with several variables. I get this error when compiling:
F:\CodeBlocks-Programs\FileManip\main.cpp|91|error: no match for call to '(std::stringstream {aka std::basic_stringstream<char>}) (std::string&)'|

If it helps, here is an example of the file that will be read from:

/ start Weapons.txt
/ Ignore lines with / proceeding them
/ Weapons will have the following format:
/ Item Description Rarity Min_Damage Max_Damage Value(in copper silver or gold)
/ Example:
/ SSword "Short Sword" common 2 4 copper 5
/ LSword "Long Sword" common 4 7 copper 10
/ SciSword "Scimitar" uncommon 25 35 silver 2
/ DragSword "Dragon Sword" rare 150 200 gold 125
/ Excal1 "Excalibur" legand 1000 1300 gold 10000
SSword "Short Sword" common 2 4 copper 5
LSword "Long Sword" common 4 7 copper 10
/ end file

I tried changing it back to iss << line; but it cout some wierd garbage:

SSword
"Short
Sword"
0
2621224
: 4201736

SSword
"Short
Sword"
0
2621224
: 4201736


Process returned 0 (0x0)   execution time : 0.140 s
Press any key to continue.
Try this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
        //use a delimiter of a space. it will only read up to the space.
        getline(file,line, ' ');

        if (line[0] == '/') //Use single quotes if evaluating a single character
            continue;        //Skip the stuff below

        iss( line );        //Put our line into the stringstream object

        //putting data in variables one by one
        iss >> Item;

        getline(file,line, ' ');
        iss( line );
        iss >> Description;

        getline(file,line, ' ');
        iss( line );
        iss >> Rarity;

        getline(file,line, ' ');
        iss( line );
        iss >> MIN_Damage;

        getline(file,line, ' ');
        iss( line );
        iss >> MAX_Damage;

        getline(file,line, ' ');
        iss( line );
        iss >> CoinType;

        // \n is a new line[ ENTER ] character. Seeing as it's the last variable,
        // this will end with a '\n'
        getline(file,line, '\n');
        iss( line );
        iss >> CoinAmount;


You were trying to add the whole line in to the int.
Last edited on
i tried your changes and get this error:

F:\CodeBlocks-Programs\FileManip\main.cpp||In function 'int main()':|
F:\CodeBlocks-Programs\FileManip\main.cpp|113|error: no match for call to '(std::stringstream {aka std::basic_stringstream<char>}) (std::string&)'|
F:\CodeBlocks-Programs\FileManip\main.cpp|117|error: no match for call to '(std::stringstream {aka std::basic_stringstream<char>}) (std::string&)'|
F:\CodeBlocks-Programs\FileManip\main.cpp|121|error: no match for call to '(std::stringstream {aka std::basic_stringstream<char>}) (std::string&)'|
F:\CodeBlocks-Programs\FileManip\main.cpp|125|error: no match for call to '(std::stringstream {aka std::basic_stringstream<char>}) (std::string&)'|
F:\CodeBlocks-Programs\FileManip\main.cpp|129|error: no match for call to '(std::stringstream {aka std::basic_stringstream<char>}) (std::string&)'|
F:\CodeBlocks-Programs\FileManip\main.cpp|135|error: no match for call to '(std::stringstream {aka std::basic_stringstream<char>}) (std::string&)'|
||=== Build finished: 6 errors, 0 warnings (0 minutes, 1 seconds) ===|

The line numbers are off. Line 113 is actually line 7. I have a lot of commented out lines.
Last edited on
I think this is one of the few remaining uses for the std::string::c_str() member function.
http://www.cplusplus.com/reference/string/string/c_str/

-Albatross
I am still having trouble. How do I get the info into the variables?
You were so close with
http://cplusplus.com/forum/beginner/60337/#msg326147

The problem there is that any whitespace will delimit what you output with the stringstream. You had a space in the description so it split your description into two parts.

Can you modify your original input file? If so, use whatever you had there and delete any spaces in the item description.
Last edited on
What if I use , between headings and delimit it somehow? No spaces except in the description? Is that possible?
Ok, I wrote a small program reading from a file to show you how I did it.
I changed the file slightly. Here is the file:
/ start Weapons.txt
/ Ignore lines with / proceeding them
/ Weapons will have the following format:
/ Item Description Rarity Min_Damage Max_Damage Value(in copper silver or gold)
/ Example:
/ SSword "Short Sword" common 2 4 copper 5
/ LSword "Long Sword" common 4 7 copper 10
/ SciSword "Scimitar" uncommon 25 35 silver 2
/ DragSword "Dragon Sword" rare 150 200 gold 125
/ Excal1 "Excalibur" legand 1000 1300 gold 10000
SSword Short_Sword common 2 4 copper 5
LSword Long_Sword common 4 7 copper 10
/ end file


I've removed the " " around the description and added underscores.

Here's the code:
includes.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <sstream>
#include <fstream>


struct weapons
{
	std::string item;
	std::string description;
	std::string rarity;
	int MIN_DMG;
	int MAX_DMG;
	std::string coinType;
	int coinAmount;
};

// function prototypes
bool load( weapons w[] );


main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include "includes.h"

int main()
{
	// max weapons
	const int wMAX = 2;

	weapons wList[ wMAX ];

	// if the load fails, exit program
	if( ! load( wList ) )
		return EXIT_FAILURE;

	for( int i = 0; i < wMAX; ++i )
	{
		std::cout << "" << wList[ i ].item << '\n';
		std::cout << "" << wList[ i ].description << '\n';
		std::cout << "" << wList[ i ].rarity << '\n';
		std::cout << "" << wList[ i ].MIN_DMG << '\n';
		std::cout << "" << wList[ i ].MAX_DMG << '\n';
		std::cout << "" << wList[ i ].coinType << '\n';
		std::cout << "" << wList[ i ].coinAmount << '\n' << '\n';
	}

	return 0;
}


load.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include "includes.h"

bool load( weapons w[] )
{
	// ifstream defaults to std::ios::in, but I use it there anyway
	std::ifstream iFile( "weapons.txt", std::ios::in );

	// if the file is NOT open
	if( ! iFile.is_open() )
	{
		std::cout << "Unable to open file...\n";

		// return, file error
		return false;
	}

	std::string input;
	std::stringstream ss;

	int index = 0;

	// while it's NOT the end of the file
	while( ! iFile.eof() )
	{
		std::getline( iFile, input, ' ' );

		//
		// check to see if the line has a comment
		//
		if( input.substr( 0, 1 ) == "/" )
		{
			// if the current line has a "/" at the start
			// get the whole line and restart the loop
			std::getline( iFile, input, '\n' );
			continue;
		}

		// set the item name
		w[ index ].item = input;

		// get description
		std::getline( iFile, input, ' ' );
		w[ index ].description = input;

		// remove the underscores from the description
		for( unsigned int i = 0; i < w[ index ].description.size(); ++i )
		{
			// if un underscore is found, at the same element in the string,
			// set it to a space ' '
			if( w[ index ].description[ i ] == '_' )
				w[ index ].description[ i ] = ' ';
		}

		// get rarity
		std::getline( iFile, input, ' ' );
		w[ index ].rarity = input;

		// get minimum damage
		std::getline( iFile, input, ' ' );
		
		// clear, add input to ss, stream to int
		ss.clear();
		ss << input;
		ss >> w[ index ].MIN_DMG;

		// get max damage
		std::getline( iFile, input, ' ' );
		
		// clear, add input to ss, stream to int
		ss.clear();
		ss << input;
		ss >> w[ index ].MAX_DMG;

		// get coin type
		std::getline( iFile, input, ' ' );
		w[ index ].coinType = input;

		// get coin amount. Last variable, line end( '\n' )
		std::getline( iFile, input, '\n' );

		ss.clear();
		ss << input;
		ss >> w[ index ].coinAmount;

		// move to the next index
		++index;
	}

	// exit after the file has finished being read
	return true;
}


Sorry it's a bit long, lol.

EDIT:
I can upload the Visual Studio solution if you like, so you can see it working.
Last edited on
Wow. That's all I can say. Okay I lied. I can say more. it may be long, however, the length serves my education. there is a lot of stuff and it is well commented. I will be able to learn to adapt parts of this program(like the sstream for example) for use i other programs. I don't often get shown stuff that is this detailed and relevant to programs I am currently writing. it's a big help. I really appreciate it. I will go through this and learn as much as I can. Then I will adapt it to the other files to see if I understand how it all works. I don't have visual studio so I have to decline the offer for the VS Solution. i do all my programming on a thumb drive using Code::Blocks. So in short, long is good and appreciated. Thank you Lynx. And thank you to everyone else.

P.S. Sometimes a concept is so difficult for me that a thorough walk through is very helpful. :)

EDIT:
I compiled the code and changed my text file like you recommended. But at the end of the output I get some extra weird garbage data? Heh? I also added cstdlib as an include for the EXIT_FAILURE. I looked through the code and since I annot yet understand it fully, I have no idea where the error is. My best guess is that something was spit out of a buffer at the end of the program. Aaaand that's where I get lost.
Last edited on
You're more than welcome!

You'll notice, in my code, I use std:: a lot. This is because I haven't used the using namespace std; directive.

Here's some info on why:
http://www.parashift.com/c++-faq-lite/coding-standards.html#faq-27.5

And yeah, I get bored a lot and end up coding other peoples problems, ahaha. I finid it easier, but obviously not quicker, to code it, rather than look through someone elses code.

I have some code at the following link too. It's not the best coding, but you may learn something from it.
As far as I remember, I've commented the source code quite well.
http://sites.google.com/site/davevisone/

And happy coding! (:
I compiled the code and changed my text file like you recommended. But at the end of the output I get some extra weird garbage data? Heh? I also added cstdlib as an include for the EXIT_FAILURE. I looked through the code and since I annot yet understand it fully, I have no idea where the error is. My best guess is that something was spit out of a buffer at the end of the program. Aaaand that's where I get lost.
Pages: 12