Reputation: 942
I am doing a little game and I am saving the player details in a txt file. Example of that txt file:
Eric 13 8 10 10 30 10 10 50 0 0 0 0
William 1 0 10 30 30 10 10 50 0 0 0 0
John 1 0 10 30 30 10 10 50 0 0 0 0
This is what I had in mind: when the player chooses to save the game while playing, the save_game
function should check if there is already any saved data. If there is, instead of appending the data to the end of the txt, it should overwrite
that specific line.
Here is my current function:
// SAVE GAME
void save_game(Player player)
{
ofstream coutfile (SaveDestiny, ios::app);
if (coutfile.is_open()) // if it opens correctly
{
// Now checking if the name already exists
string imported_name;
ifstream cinfile (SaveDestiny); // opens file that contains the saved games
cinfile >> imported_name; // getting first element of file
bool j = 0; // j = 0 while the strings don't match. j = 1 when the string was found
while (cinfile >> imported_name) // while the end of file is not reached
{
if (player.name.compare(imported_name) == 0) // if the strings are the same, overwrite data
{
j = 1;
coutfile << " \r" << endl;
break;
}
else // if the strings are different, keep reading
{
cinfile >> imported_name;
}
}
// Continuing...
coutfile << player.name << " " << player.level << " " << player.exp << " " << player.max_exp << " "
<< player.hp << " " << player.max_hp << " " << player.mp << " " << player.max_mp << " "
<< player.gold << " " << player.weapon << " " << player.shield << " " << player.heal_spell << " "
<< player.attack_spell << endl;
}
else
{
ofstream coutfile (SaveDestiny, ios::app);
coutfile << "test";
cout << "Unable to open file";
cin.get();
}
draw_rectangle(37,8,72,14,15); // white limits
draw_rectangle(39,9,70,13,9); // blue background
cor(9,15);
gotoxy(50,10);
cout << "GAME SAVED!";
gotoxy(41,12);
cor(9,14);
cout << "Press <Enter> to continue... ";
cin.get();
}
Upvotes: 0
Views: 3398
Reputation: 942
Ok I've managed to get around the problem and now it's working brilliantly! :D
First, the function
checks if the player name already is on the txt
. I created a enable variable j
. When j=1
, the name exists and the data needs to be overwritten
! When j=0
, the function will append
the data to the txt right away.
Ok, let's say j=1
. The function determines the number of lines in txt
. It then creates a vector
with two vectors inside: the name
, and the game variables
.
After that, the function deletes the previouscontent of txt
file. And writes the content of the vector to the txt
, except the data that needs to be overwritten (it will skip writing that part to the txt
), because at the end of the function, that new data will be written. :D I hope I made myself clear enough. Sorry if someone doesn't understand what I wrote...
Here is my new save_game
function:
// SAVE GAME
void save_game(Player player)
{
ofstream coutfile (SaveDestiny, ios::app);
if (coutfile.is_open()) // if it opens correctly
{
string imported_name;
ifstream cinfile (SaveDestiny); // opens file that contains the saved games
bool j = 0;
// Now checking if the name already exists
while (cinfile >> imported_name) // while the end of file is not reached
{
if (player.name.compare(imported_name) == 0) // if the strings are the same, overwrite data
{
j = 1; // enable overwrite
break;
}
// if the strings are different, keep reading
}
// at this point: j = 0 to append to end. j = 1 to overwrite.
// Overwriting data
if (j == 1)
{
ifstream cinfile (SaveDestiny);
// now determining the size of the vector (number of lines in txt)
int line_numbers = 0;
string line;
while (getline(cinfile, line))
{
line_numbers++;
}
cinfile.close(); // closing
ifstream cinfile2 (SaveDestiny); // reopening to read from the beginning
// now creating the vector with the saves
vector<vector<string>> temp_saves(line_numbers, vector<string>(2));
string name2;
string values;
for (unsigned int x = 0; x < temp_saves.size(); x++)
{
cinfile2 >> name2;
getline(cinfile2, values);
temp_saves[x][0] = name2;
temp_saves[x][1] = values;
}
coutfile.close(); // closing output file
ofstream coutfile2 (SaveDestiny); // reopening in overwrite mode
// delete all saves.txt, copying vector content to txt (except the one we want to overwrite)
for (unsigned int x = 0; x < temp_saves.size(); x++)
{
if ( temp_saves[x][0].compare(player.name) != 0)
{
coutfile2 << temp_saves[x][0] << temp_saves[x][1] << endl;
}
}
coutfile2.close(); // closing output file
}
// Appending new data...
ofstream coutfile3 (SaveDestiny, ios::app); // reopening in append mode
coutfile3 << player.name << " " << player.level << " " << player.exp << " " << player.max_exp << " "
<< player.hp << " " << player.max_hp << " " << player.mp << " " << player.max_mp << " "
<< player.gold << " " << player.weapon << " " << player.shield << " " << player.heal_spell << " "
<< player.attack_spell << endl;
}
else
{
ofstream coutfile (SaveDestiny, ios::app);
cout << "Unable to open file";
cin.get();
}
draw_rectangle(37,8,72,14,15); // white limits
draw_rectangle(39,9,70,13,9); // blue background
cor(9,15);
gotoxy(50,10);
cout << "GAME SAVED!";
gotoxy(41,12);
cor(9,14);
cout << "Press <Enter> to continue... ";
cin.get();
}
Upvotes: 0
Reputation: 171263
On most modern filesystems files are not "line-based" (or "record-based") they are character-based so you can't "overwrite a line". The old line might be 20 characters long and the new one would be 24 characters, in which case it would overwrite the old line and the first 4 characters of the next line. To make this work you would have to "push" everything after the line later in the file, which isn't possible with C++ (or C) IO facilities.
One option would be to write all lines with a fixed length, say 50 characters, so that overwriting the 3rd line involves replacing characters 100 to 149, even if the line only actually needs 24 characters.
Another option would be to keep the file in memory in a record-based form and write out the entire file every time you change it (or at least write out the new line and all lines that come after it)
Upvotes: 3