ListBox.FillSaveGameList(); and Overwriting Save Games

Started by Kurdt, Mon 07/08/2006 21:20:20

Previous topic - Next topic

Kurdt

I used ListBox.FillSaveGameList(); code in my custom Save GUI's list box and it works fine, but when I do the same thing for my Restore GUI's list box, I get nothing. I've checked and double-checked and triple-checked the code and it should be working, but it just doesn't fill my load list with saves. What gives?

On another note, I've been trying to get my Save GUI to overwrite save games if the input to the Text Box is the same as the name of a previously saved game (In the Sierra style). I've got this code:

Code: ags

int saves;

#sectionstart SaveButton_Click//SAVE BUTTON IN THE CONTROL PANEL GUI
function SaveButton_Click(GUIControl *control, MouseButton button)
{gControl.Visible = false;
gSavegame.Centre();
gSavegame.Visible = true;
saves = (SaveList.ItemCount);
if (saves > 19) {
  DisplayMessage(990);
  }
}
#sectionend SaveButton_Click//SAVE BUTTON IN THE CONTROL PANEL GUI

#sectionstart SavegameButton_Click  // DO NOT EDIT OR REMOVE THIS LINE
function SavegameButton_Click(GUIControl *control, MouseButton button) {
String input = SaveText.Text;
String item = SaveList.Items[SaveList.SelectedIndex];
if (input.CompareTo(item) == 0) { // i.e. strings match
SaveGameSlot(SaveList.SelectedIndex, SaveText.Text);
}
else {
SaveGameSlot(saves, SaveText.Text);
SaveList.AddItem(input);
}
gSavegame.Visible = false;
gIconbar.Visible = true;
}
#sectionend SavegameButton_Click  // DO NOT EDIT OR REMOVE THIS LINE

However, every time I try to save a game with this code, the game crashes and tells me I've got an "invalid index specified." I've scoured the manual, this thread and this thread, but I've still come up with nothing. What's the story here?

I swear to God if I ever get this down I'm making a tutorial. No one should have to search as much as I did for anything regarding this engine, much less something so universally desired as custom Save and Load GUIs.
"The reason why so few good books are written is that so few people who can write know anything."

GarageGothic

#1
It would help if you pointed out in which line you get the error message. But I think the problem is that you're mixing up savegameslots and their indexes.

Instead of:
Code: ags

SaveGameSlot(SaveList.SelectedIndex, SaveText.Text);


try:
Code: ags
SaveGameSlot(SaveList.SaveGameSlots[SaveList.SelectedIndex], SaveText.Text);

Kurdt

I'm getting the error at the "String item = SaveList.Items[SaveList.SelectedIndex];" line. I'll go punch in that code and see what happens.

EDIT: The code you gave me told me that "SaveGameSlots" (SaveList.SaveGameSlots[etc....) isn't a public member of ListBox. What did you mean to type there?
"The reason why so few good books are written is that so few people who can write know anything."

GarageGothic

#3
And at the point where the game crashes, do you actually have an item selected?

Try setting up a check before getting the Item to see if it still crashes then:
Code: ags
String item = ""; //to avoid errors in later part if the string remains null
if (SaveList.SelectedIndex > -1) item = SaveList.Items[SaveList.SelectedIndex];


edit: In regards to the error, SaveGameSlots should indeed work. You have used SaveList.FillSaveGameList() earlier in the code, right?

edit 2: Wait a minute, what is this code
Code: ags
SaveList.AddItem(input);
meant to do? You shouldn't add anything to the save list manually. Just use SaveList.FillSaveGameList() again if you want to update it.

Kurdt

The AddItem is meant to add the new save to the list when the player saves a new game. How does FillSaveGameList add a new save to the list?

And at this particular moment, I have no games saved so I'm not able to have anything selected since nothing exists yet. I'm just trying to save one game. I want the code to check to see if what's typed in the TextBox is the same as a previously saved game, perhaps the one that's selected. If it is, then overwrite. If it's not or there's no item selected, just save a new game.

And I did use FillSaveGameList earlier, in the SaveList section. It's saying that SaveGameSlot doesn't belong as a ListBox item. It only gave me that error when I typed in SaveList.SaveGameSlots. I see nowhere in the manual or any other FAQ that's ever used SaveGameSlot like that and plural.

Let me go punch that new stuff in and see what happens...

EDIT: That worked to save the game, but it's doing a strange thing with the box. I try to click on another save in the list to save over it and it won't let me. It highlights that save for a split second and then automatically goes the the top of the list. Sometimes when I click on an item it'll get pushed to the top of the list as well. I don't understand that.

Also, is it possible for me to make it to where if the words typed in the TextBox match up with any save game in the list, regardless of whether or not it's selected, it will overwrite that save?
"The reason why so few good books are written is that so few people who can write know anything."

GarageGothic

#5
FillSaveGameList will add the new save to the list, because it updates the ListBox to contain the saves that are in the game directory. So the game you just saved in the line above should be added. AddItem is likely to screw up the savegame indexes, so that should be avoided.
HOWEVER, I fucked up, because SaveGameSlot only saves at the very end of the function where it's called. So running FillSaveGameList wouldn't help unless you run it afterwards. Most people close the save gui the moment that the game is saved, so this usually isn't an issue. AND, that seems to be the case here too (you call gSavegame.Visible = false; right after saving). So don't bother with the AddItem line.

WHERE do you call FillSaveGameList, since I don't see it in the current code? I would suggest doing it just before displaying the Save gui, to make sure that it's up-to-date:

Code: ags
gSavegame.Visible = true;
SaveList.FillSaveGameList();
saves = (SaveList.ItemCount);



Kurdt

I have it in the SaveList_SelectionChanged section. I didn't copy/paste it here because it didn't seem important. Should I even bother with having a section for that if I'm going to put it somewhere else?

EDIT: I put the FillSaveGameList code where you said and it worked (filling the RestoreList as well). However, I've still got that problem where it won't let me select any save but the very first one and it won't overwrite a game that's not selected, regardless of whether or not the input to the SaveText box is the same as the save's name. How do I rid myself of this?
"The reason why so few good books are written is that so few people who can write know anything."

GarageGothic

If you still have FillSaveGameList it in the SaveList_SelectionChanged, please remove it! That's the cause of the trouble I'm quite sure. Everytime you change your selection, it updates the list, thus bumping the selection to the top.

Kurdt

Ah, well, there you go. What the hell do I need the SelectionChanged section for, then, anyway?

Still trying to figure out the text box thing...
"The reason why so few good books are written is that so few people who can write know anything."

GarageGothic

#9
Ok, for the text box issue you basically have to search through all the savegames for a matching text, so you want to do something like this:

Code: ags

int currentsaveslot;
bool foundsamename;
while ((currentsavegame <= SaveList.ItemCount) && (foundsamename == false)){
    if (SaveText.Text == SaveList.Items[currentsaveslot])  foundsamename = true;
    else currentsaveslot++;
    }
if (foundsamename == true) SaveGameSlot(SaveList.SaveGameSlots[currentsaveslot], SaveText.Text);


As for SelectionChanged, you could use that if you for example want to copy the name of the selected savegame to the textbox (so the player can modify the name of an existing game before overwriting it).

Kurdt

Really? Awesome! That's what I'd like to get done as well. In the meantime, I'm going to implement that new code and see what it do.

Thanks for all your help, by the by.
"The reason why so few good books are written is that so few people who can write know anything."

Kurdt

Hello, it's me again. I've been away doing real life crap and have only now been able to implement that code. At the moment I'm getting an error that says that "currentsaveslot" is undefined. I'm not quite sure what it should be defined AS, though. Do you have an idea? I literally copied and pasted the code in this thread.

EDIT: I noticed the code given to me was erroneous in that the while statement names "currentsavegame" and the int is currentsaveslot, so a quick name change fixed that. However, now it's telling me that SaveList.Items specifies an invalid index.

Also, it overwrites the save game that's selected regardless of whether or not the text in the TextBox is the same as the text selected. How do I get that to go away? I only want it to overwrite a save game if the text in the text box matches the text of a game saved, and if a save game is selected it fills the text box with its text.
"The reason why so few good books are written is that so few people who can write know anything."

Ashen

'undefined token' errors (which I'm guessing you got) mean you've tried to use a variable (int, String, or call a function) that doesn't exist. You solved this yourself, when you corrected GG's typo.

The 'invalid index' problem, I think, is the same one that's already been dealt with in this thread - by GG, in fact:

Quote from: GarageGothic on Mon 07/08/2006 21:39:39
It would help if you pointed out in which line you get the error message. But I think the problem is that you're mixing up savegameslots and their indexes.
Instead of:
Code: ags

SaveGameSlot(SaveList.SelectedIndex, SaveText.Text);

try:
Code: ags
SaveGameSlot(SaveList.SaveGameSlots[SaveList.SelectedIndex], SaveText.Text);


I don't know why it overwrites regardless of the text matching, that code looks like it should work.
EDIT: What other code do you have? As-is, that code (if I've read it right) shouldn't save AT ALL if the Text doesn't match. Is there any other code being called that might be affecting it? (e.g. in Selection_Changed, SavegameButton, somewhere else...)
EDIT2:
Quote
I only want it to overwrite a save game if the text in the text box matches the text of a game saved, and if a save game is selected it fills the text box with its text.
Have you coded this yet? If so, when you select a slot SaveText.Text will be updated to the name of the selected game - so obviously it'll match, and the selected game will be overwritten.
I know what you're thinking ... Don't think that.

Kurdt

I think I still have the old code in there as well and it may be getting confused. Once I get this invalid index thing fixed I'll eliminate that old code and see if it works. I'll be riiiight back!

EDIT: Well, I changed the "currentsaveslot" in the SaveList.Items property to "SaveList.SelectedIndex", but now it's not saving games at all. I click the save button and nothing happens. What exactly do you have in mind here for the Items property?

EDIT2:
QuoteHave you coded this yet? If so, when you select a slot SaveText.Text will be updated to the name of the selected game - so obviously it'll match, and the selected game will be overwritten.
GG said that the code to make that happen should be put in SelectionChanged, but I still have no idea what that code would even look like, so no I haven't coded that in yet.
"The reason why so few good books are written is that so few people who can write know anything."

Ashen

That was a mistake on my part, sorry. I'm not used to the 2.72 code yet, misread it - it should have been OK as it was.

I think I see what the problem actually is, though (or a problem, at least):

Code: ags

while ((currentsavegame <= SaveList.ItemCount) && (foundsamename == false)){


This means it could be checking SaveList.Items[SaveList.ItemCount] - since the index of the last item in the ListBox is SaveList.ItemCount -1, that would be an 'invalid index'. Changing the '<=' to just '<' should hopefully solve the invalid index thing (or at least head off a future error).
I know what you're thinking ... Don't think that.

Kurdt

I took away the = and it eliminated the invalid index error, but nothing still happens when I try to save. I put the old code back in and I still overwrite the SelectedIndex save regardless of whether or not it's the same text. To top it off, it doesn't fill the SaveText box with the save's name when I select it. Here's the code as it is for my entire save apparatus:

Code: ags
int saves;
int currentsaveslot
bool foundsamename;

#sectionstart SaveButton_Click//SAVE BUTTON IN THE CONTROL PANEL GUI
function SaveButton_Click(GUIControl *control, MouseButton button)
{gControl.Visible = false;
gSavegame.Centre();
gSavegame.Visible = true;
SaveList.FillSaveGameList();
saves = (SaveList.ItemCount);
if (saves > 19) {
  DisplayMessage(990);
  }
}
#sectionend SaveButton_Click//SAVE BUTTON IN THE CONTROL PANEL GUI

#sectionstart SaveList_SelectionChanged  // DO NOT EDIT OR REMOVE THIS LINE
function SaveList_SelectionChanged(GUIControl *control) {

}
#sectionend SaveList_SelectionChanged  // DO NOT EDIT OR REMOVE THIS LINE

#sectionstart SaveText_Activate  // DO NOT EDIT OR REMOVE THIS LINE
function SaveText_Activate(GUIControl *control) {

}
#sectionend SaveText_Activate  // DO NOT EDIT OR REMOVE THIS LINE

#sectionstart SavegameButton_Click  // DO NOT EDIT OR REMOVE THIS LINE
function SavegameButton_Click(GUIControl *control, MouseButton button) {
String input = SaveText.Text;
String item = ""; //to avoid errors in later part if the string remains null
while ((currentsaveslot < SaveList.ItemCount) && (foundsamename == false)){
    if (SaveText.Text == SaveList.Items[currentsaveslot])  foundsamename = true;
    else currentsaveslot++;
    }
if (foundsamename == true) SaveGameSlot(SaveList.SaveGameSlots[currentsaveslot], SaveText.Text);
if (input.CompareTo(item) == 0) { // i.e. strings match
SaveGameSlot(SaveList.SaveGameSlots[SaveList.SelectedIndex], SaveText.Text);
}
else {
SaveGameSlot(saves, SaveText.Text);
}
gSavegame.Visible = false;
gIconbar.Visible = true;
}
#sectionend SavegameButton_Click  // DO NOT EDIT OR REMOVE THIS LINE

#sectionstart DeleteSaveButton_Click  // DO NOT EDIT OR REMOVE THIS LINE
function DeleteSaveButton_Click(GUIControl *control, MouseButton button) {
DeleteSaveSlot(SaveList.SelectedIndex);
SaveList.FillSaveGameList();
}
#sectionend DeleteSaveButton_Click  // DO NOT EDIT OR REMOVE THIS LINE

#sectionstart CancelSaveButton_Click  // DO NOT EDIT OR REMOVE THIS LINE
function CancelSaveButton_Click(GUIControl *control, MouseButton button) {
gSavegame.Visible = false;
gIconbar.Visible = true;  
}
#sectionend CancelSaveButton_Click  // DO NOT EDIT OR REMOVE THIS LINE


As is seen, I'm toying around with deleting savegames as well. When I hit my delete button it deleted the saves just fine until there was just one save, then it wouldn't let me delete it and now it only overwrites that save. If I take all the code aside from the while statement out of the Savegamebutton part it doesn't do anything.
"The reason why so few good books are written is that so few people who can write know anything."

CMK2901

I recently added an article in the AGSwiki about making your own save/load dialogs, complete with delete buttons.  If you're still having problems, take a look at that.  I know for a fact the code works; I'm using it right now.  :)

All you'd probably have to do is change some element names and it would be fine.
Science Fiction
Currently writing and developing technology/techniques
Story/Puzzles: 48%
Graphics: 5%
Overall: 5%

Kurdt

Good tutorial and it definitely helped me a lot, but like you said it's got the fatal flaw of only checking against the hilighted save. I'm going to make an attempt at merging your code with GG's code and see if I can get something working.
"The reason why so few good books are written is that so few people who can write know anything."

Kurdt

Okay, I can only assume that the suggested code doesn't work at all, because it still only compares against the SelectedIndex property.

Can somebody explain to me the exact property of a savegame? For example, how does it remember its name, how does FillSaveGameList call up that name, etc.? How do savegame files in and of themselves work, essentially? What's the concept behind them?
"The reason why so few good books are written is that so few people who can write know anything."

CMK2901

Well, from what I understand...

1) How does FillSaveGameList work?

All that FillSaveGameList() does is run through the save games stored in "savegameindex[]", and uses the "desc" property in the save file to put the games in the list box in order of slot number.

2) How do save files work?

To save files, you use the function "SaveGameSlot(slot, desc)".  What this does is save your games state to a file in the "Compiled" directory and it then references this save in "savegameindex[]".

So, if you save a game called "Bob" at the first place on the list box, it would be SaveGameSlot(1, "Bob").  This will save the game state as the file "agssave.001" in the "Compiled" directory.  It would then make a reference to "savegameindex[]" so that "savegameindex[1]" would then point to the saved game "Bob".

Right, now we have to add list box code, so we can save dynamically.
"SaveGameSlot(lstBox.ItemCount +1, "Bob") would always save a new file.  However, if we want to overwrite an old file, the reference to it is in "savegameindex[]", and the easiest way to identify it is to use the "SelectedIndex" property, since FillSaveGameList() fills the list box with the same numbers as "savegamelist[]".

So, to overwrite, we'd use: SaveGameSlot(savegameindex[lstBox.selectedIndex], "Bob");

So, if you wanted to avoid the bug that I currently have listed in the tutorial, it would be a simple matter of, rather than checking against selected index, running through the entire list and checking for doubles.

Anyway, I hope this helps.  If you need more info, I'll do my best.

EDIT: Considering what I said above, I've fixed the code in the AGSwiki.  It now checks all the saves, not just the highlighted one.  As far as I can tell, it now functions perfectly.
Science Fiction
Currently writing and developing technology/techniques
Story/Puzzles: 48%
Graphics: 5%
Overall: 5%

SMF spam blocked by CleanTalk