I'm making my own Save/Restore GUI's using several tutorials that are for earlier versions of AGS. I'm making progress, I think I actually have the Save GUI done right. But what I can't figure out is how to make a proper Restore GUI. Specifically, how do you make it so that the saved games in the Saved GUI list box come up into the Restore GUI list box.
The Save GUI:
//Save Game
if (interface==SAVEGUI) {
if (button==0) {
bg_save_idx = save_listbox_chris.ItemCount;
if (bg_save_idx<20) {
save_textbox_chris.GetText(input);
save_listbox_chris.AddItem(input);
SaveGameSlot(bg_save_idx+1, input);
gSavegui.Visible=false;
}
}
}
That seems to save the games okay. Although I don't really know unless I can get the Restore GUI to work.
Here's what I've tried for the Restore GUI:
//Restore Game
int bg_restore_idx;
string bg_restore_buf;
if (interface==LOADGUI) {
if (button==0) {
bg_restore_idx= restore_listbox_chris.SelectedIndex;
if (bg_restore_idx==-1) {
Display("Please make a selection.");
}
else
{
restore_listbox_chris.GetItemText(restore_listbox_chris.SelectedIndex, bg_restore_buf);
RestoreGameSlot(savegameindex[bg_restore_idx]);
}
}
}
}
But when the Restore GUI comes up, there's no saved games to choose from.
Has anybody tried this using version 2.7 that works?
That seems OK, as far as it goes. Where do you turn the GUI on (F7 keypress, button on another GUI, both, somewhere else)?
Wherever, there should also be a ListBox.FillSaveGameList() command to, well, fill the list box with the save games, e.g.:
restore_listbox_chris.FillSaveGameList();
gLoadgui.Visible = true;
(There should also be something similar to fill the Save GUI list, when it turns on.)
Also, as a matter of good practice, since you're using 2.7 put the commands in individual control functions rather than the obsolete interface_click it looks like you're using. (But this isn't vital, as interface_clickstill works.)
Thanks! I should have thought of that.
One other question: is there a way to clear the text box in the Save GUI whether either the save or cancel button is pushed? Right now, if you type anything there and hit save, the text stays and you have to back space it to clear it every time.
EDIT: Actually I'm thinking that might not be possible. Perhaps I was thinking about the Cirque De Zale game where there's numbered slots in the save GUI to type in. How would one accomplish that?
The second way is trickier, and I don't know it off the top of my head (not actually having played CdZ).
The first way, just use TextBox.SetText(...) in the Save/Cancel button scripts, e.g.:
save_textbox_chris.SetText("");
(In 2.7, anyway. 2.71 and the new string methods might be different).
Give the manual a look through (which you really should have already) - even if you don't need a particular function just now, knowing it exists will save you having to ask in the future.
Thanks again, Ashen. I'll try this.
Since any tutorials I've found are for older versions, I hope it's obvious that I've pored over the manual to figure this out for the newer version. But sometimes even the manual doesn't help if you don't know what you're looking for. (There's a lot of info there). But at least you've put me in the right direction.
Yes, it can be confusing to take in all at once.
I didn't mean it as a 'RTFM, n00b', just that you should take the time to familiarise yourself with it in general. Also - as you might've noticed - most of the obsolete functions (e.g. Get/SetTextBoxText(gui, object, string)) link to their current versions, which should help with updating most code.
Okay, just one more question regarding this and I think it's done.Ã, It's overwriting a saved game slot if you type in the same name that's in the listbox or highlight an existing game name and then save.
I know you'd have to say something like
if (save_textbox_chris.GetText(input) ==save_listbox_chris.GetItemText(save_listbox_chris.SelectedIndex, input) {
overwrite what's in the listbox.Ã, Something like that.Ã, :-\
I'm just not able to get my head around it. Can someone help?
If you're using 2.7, you can't compare strings using the '==' operator - you need to use StrComp(string1, string2) or StrCaseComp(string1, string2) (StrComp() is case sensitive, StrCaseComp() isn't).
Also, you'd need to use a second string to store the item text for comparison, e.g.:
string input;
string item;
save_textbox_chris.GetText(input);
save_listbox_chris.GetItemText(save_listbox_chris.SelectedIndex, item);
if (StrComp (input, item) == 0) { // i.e. strings match
// overwrite slot
}
else {
// save new slot
}
(You should probably include a confirmation option, to stop people accidentally overwriting slots.)
In 2.71+, you can use '==', but I'd still recommend using different Strings for the TextBox and ListBox.
Another thing you might want to do (if you haven't already) is add something to the ListBox's SelectionChanged function, to set the TextBox text to the name of the selected save slot.
Is there an overwrite slot command? From other posts, it looks like you would have to delete that same saved game and then save it again as new. Or is there a simpler way in 2.7? If not, how do you delete that exact saved game name?
No need to delete, just save over it with SaveGameSlot(), e.g.:
SaveGameSlot (savegameindex[save_listbox_chris.SelectedIndex], input);
Great! It works when I type in a name that is also in the list box. But then about highlighting a name in the listbox and saving:
Quote
Another thing you might want to do (if you haven't already) is add something to the ListBox's SelectionChanged function, to set the TextBox text to the name of the selected save slot.
I'm not sure what you meant here.
It seems, from the code you've posted, like you want it that if you select an existing slot in the ListBox, and type the same name into the TextBox, it overwrites the slot.
By double clicking on the ListBox in the editor, you can set code that runs every time the player changes the selection, just like you'd set the code for buttons (if you weren't using interface_click). If you added something like:
save_listbox_chris.GetItemText(save_listbox_chris.SelectedIndex, item);
save_textbox_chris.SetText(item);
You'd save the player having to type the existing save game name.
You can still do this with interface_click (I'd just forgotten you were using it), just do an if (button == .. condition for the ListBox's number, or use:
if (button == save_listbox_chris.ID) {
save_listbox_chris.GetItemText(save_listbox_chris.SelectedIndex, item);
save_textbox_chris.SetText(item);
}
It's not important - it's just something I think is neat.
Okay, I've put the code into the "save" control function like you suggested.
Here's what I put:
int bg_save_idx;
string input;
string item;
bg_save_idx = save_listbox_chris.ItemCount;
if (bg_save_idx<20) {
Ã, save_textbox_chris.GetText(input);
Ã, save_listbox_chris.AddItem(input);
Ã, SaveGameSlot(bg_save_idx+1, input);
Ã, gSavegui.Visible=false;
save_listbox_chris.GetItemText(save_listbox_chris.SelectedIndex, item);
if (StrComp (input, item) == 0) {
Ã, SaveGameSlot (savegameindex[save_listbox_chris.SelectedIndex], input);
}
}
}
It looks right to me.Ã, The funny thing is, it worked for a while.Ã, It would overwrite a saved game that was already in the listbox.Ã, Ã, But now it doesn't.Ã, It'll repeat the same name into the listbox.Ã, But isn't it correct?
Also in the saved GUI listbox control function I put this:
save_listbox_chris.GetItemText(save_listbox_chris.SelectedIndex, item);
save_textbox_chris.SetText(item);
Now that works in that it will put what I highlight from the listbox into the textbox, but then I can't make it overwrite that saved game.Ã, I know I'm missing something there, but I can't figure out what.
The way you've got it, it'll save to a new slot and turn the GUI off, before even checking the selected slot. AFAIK, closing the GUI 'resets' the selected index, meaning the match would be lost. Try:
int bg_save_idx;
string input;
string item;
bg_save_idx = save_listbox_chris.ItemCount;
save_textbox_chris.GetText(input);
save_listbox_chris.GetItemText(save_listbox_chris.SelectedIndex, item);
if (StrComp (input, item) == 0) {
SaveGameSlot (savegameindex[save_listbox_chris.SelectedIndex], input);
gSavegui.Visible=false;
} // i.e. Check if TextBox and ListBox match. If so , save ...
else if (bg_save_idx<20) { // And if not, AND you have less than 20 slots, save a new one
save_listbox_chris.AddItem(input); // This line seems pointless to me
SaveGameSlot(bg_save_idx+1, input);
gSavegui.Visible=false;
}
// You might want to include a 'No match, and already have 20 slots' condition here.
} // I guess this is the end of the button condition?
The 'pointless' line doesn't really serve a purpose, as the GUI is turned off before you'd notice the new item, and the ListBox is re-filled with the savegame list the next time you turn it on - so you don't need to manually add it here.
Almost there I think.Ã, The only problem with this last scripting is this line:
save_listbox_chris.GetItemText(save_listbox_chris.SelectedIndex, item);
It works if there's already a saved game in the listbox, but if you're starting fresh, there's nothing in the listbox to get, and the game crashes.
True. Add a check for save_listbox_chris.SelectedIndex != -1 when you get the ListBox text, i.e.:
// blah blah
save_textbox_chris.GetText(input);
if (save_listbox_chris.SelectedIndex != -1) save_listbox_chris.GetItemText(save_listbox_chris.SelectedIndex, item);
if (StrComp (input, item) == 0) {
//blah blah
Now, the only problem would be if nothing is selected (or there's nothing TO select), and the player enters a blank name (it'll get a 'match' and try to save to slot -1). But, being able to save with a blank name is a bit of a problem anyway. To totally idiot-proof it, you might want to add something to abort if the TextBox was left blank, e.g.:
save_textbox_chris.GetText(input);
if (StrComp (input, "") == 0) {
Display("You must enter a name for your save game!");
return;
}
if (save_listbox_chris.SelectedIndex != -1) save_listbox_chris.GetItemText(save_listbox_chris.SelectedIndex, item);
// etc...
Just one more thing regarding if the listbox has more that 20 slots filled.Ã, I've tried several things but they don't work and ends up messing other stuff up.
Maybe you could let me know if I'm close.
int bg_save_idx;
string input;
string item;
bg_save_idx = save_listbox_chris.ItemCount;
save_textbox_chris.GetText(input);
save_listbox_chris.GetItemText(save_listbox_chris.SelectedIndex, item);
if (StrComp (input, item) == 0) {
Ã, SaveGameSlot (savegameindex[save_listbox_chris.SelectedIndex], input);
Ã, gSavegui.Visible=false;
}
else if (bg_save_idx<20) {
Ã, Ã, SaveGameSlot(bg_save_idx+1, input);
Ã, gSavegui.Visible=false;
}
else if (bg_save_idx>20) {
SaveGameSlot (savegameindex[save_listbox_chris.SelectedIndex], input);
Ã, gSavegui.Visible=false;
}
But two "else if's" like this won't work.Ã, And it doesn't overwrite any other way I try this.
How would you put that exactly? (Once I get this part, I think I'm done with this.)
Thatlooks almost exactly right, but you'll need to make it 'greater than or equal to 20' (bg_save_idx>=20), rather than just 'greater than' - which obviously won't run if there are EXACTLY 20 slots.
Also, you should add a check that a slot is selected or you'll get a crash (similar to the one you were getting with GetItemText and an empty ListBox):
else if (bg_save_idx>=20) {
if (save_listbox_chris.SelectedIndex != -1) {
SaveGameSlot (savegameindex[save_listbox_chris.SelectedIndex], input);
gSavegui.Visible=false;
}
else Display ("Select a slot to overwrite.");
}
And again, you might want to add a confirmation to prevent accidental overwriting.
Just one final thing.Ã, I made a new GUI that pops up for the confirmation.Ã,Â
For the "Yes" button, I put this code:
string input;
Ã, if (save_listbox_chris.SelectedIndex != -1) {
Ã, Ã, SaveGameSlot (savegameindex[save_listbox_chris.SelectedIndex], input);
Ã, Ã, gSavegui.Visible=false;
Ã, Ã, gConfirm.Visible=false;
Ã, Ã, }
But then instead of the save name, it puts this strange symbol in the save listbox slot. I didn't think it would be complicated, probably just a small thing.
Do you actually have another declaration of string input; in the button's condition? That would explain why it's not saving with the name (it's dealing with a new, blank instance of input), but not why it assigns it a random symbol. It could be setting an ascii character for input - does the symbol change at all, or is it always the same one?
Whatever, you either need to make input accessable by all GUIs (put the declaration somewhere in the global script outside of and before interface_click, and delete all other string input; lines), or get the TextBox text again, before saving. Either of them should resolve this.
The symbol I was getting was always the same one - a "c" with a circle around it.
I've put the string at the beginning of the global script and now everything works.
That's it! This save/load GUI is now complete. Thanks Ashen for all your help and patience! I really really appreciate it!
This thread went much longer than I thought it would. Hopefully it'll be helpful to anyone else who wants to make a save/load GUI from scratch using version 2.7.
So, wait: Can we finally label this SOLVED?
Yeah, I'd say so. The one thing I noticed at this point is that when the 20 slots are full it will overwrite the game at the top of the list. But if you choose a game that's farther down, it will repeat it.
Maybe I'm just being picky, but I can't figure out why that would happen.
Dang, and I thought we were done with this.
That's not being picky, it sounds like a fairly major - at least majorly annoying - bug.
Can you describe exactly what's happening? If you select the top savegame it overwrites OK, but otherwise it creates a new game, over the 20?
One thing to remember: ListBox.FillSaveGameList() sorts chronologically, with the most recent save at the top - so when you overwrite a game, it'll jump to the top of the list. Is this what's happening? If so it's not a bug and, AFAIK, it's unavoidable without manually scripting the array (not using FillSaveGameList() or (savegameindex[..]).
It's exactly the way you described it. You've named the saved games from the top 20, 19, 18. If you then saved the game as 18, it will replace game 20, but there will still be a game 18. So now 18, 19, 18.
I don't know what could be causing that ... It should go:
20
19
18
17
etc
Then, if you overwrite 18:
18
20
19
17
etc
How does the restoring work? Does game 20 still restore to the same point or has it in fact been overwriten?
One possibility is that save_listbox_chris.SelectedIndex is being reset to 0 when gConfirm is switched on. Try declaring an int outside of interface_click, and setting that before you turn on gConfirm, i.e
selected_slot = save_listbox_chris.SelectedIndex;
gConfirm.Visible = true;
Then, for the 'Yes' button:
if (selected_slot != -1) {
SaveGameSlot (savegameindex[selected_slot], input);
gSavegui.Visible=false;
gConfirm.Visible=false;
}
No, it still happens. And just to make sure , I tried this without using the Confirm GUI, and the same thing happens.
Also, the game name at the top of the list restores fine, but when I restore the same game name lower down the game crashes.
This is very annoying. (And I don't suppose it's much fun for you, either ;D)
Can you post the whole code for SAVEGUI, and CONFIRM? (For all buttons - and what button is what). There might be something caused by adding some, then changing it, then adding some more, etc, that's not obvious looking at it in pieces but that fresh eyes could pick out.
Okay, here it all is.Ã, And just to let you know, each button's scripting is in its own control function, not in the interface_click function.
gSavegui
save_button = button 0:
int bg_save_idx;
bg_save_idx = save_listbox_chris.ItemCount;
save_textbox_chris.GetText(input);
if (StrComp(input, "")==0) {
Ã, Display("You must enter a name to save!");
Ã, return;
Ã, }
if (save_listbox_chris.SelectedIndex!=-1) save_listbox_chris.GetItemText(save_listbox_chris.SelectedIndex, item);
if (StrComp (input, item) == 0) {
Ã, Ã, SaveGameSlot (savegameindex[save_listbox_chris.SelectedIndex], input);
Ã, gSavegui.Visible=false;
}
else if (bg_save_idx<20) {
Ã, Ã, SaveGameSlot(bg_save_idx+1, input);
Ã, gSavegui.Visible=false;Ã,Â
Ã, }
Ã, else if (bg_save_idx>=20) {Ã, Ã,Â
selected_slot = save_listbox_chris.SelectedIndex;
gConfirm.Visible = true;
}
Ã, else Display ("Select a slot to overwrite.");
}
gLoadgui
restore_button = button 0:
int bg_restore_idx;
stringÃ, bg_restore_buf;
Ã, Ã, bg_restore_idx= restore_listbox_chris.SelectedIndex;Ã, Ã,Â
if (bg_restore_idx==-1) {
Ã, Ã, Display("Please make a selection.");
Ã, Ã, return;
}
else {
restore_listbox_chris.GetItemText(restore_listbox_chris.SelectedIndex, bg_restore_buf);
RestoreGameSlot(savegameindex[bg_restore_idx]);Ã, Ã,Â
gLoadgui.Visible=false;
}
}
gConfirm
yes_button = button 1:
if (selected_slot != -1) {
Ã, Ã, SaveGameSlot (savegameindex[selected_slot], input);
Ã, Ã, gSavegui.Visible=false;
Ã, Ã, gConfirm.Visible=false;
Ã, Ã, }
All other ints and strings are declared at the beginning of the global script.
Well, there's a little problem with the last condition of the Save button:
else Display ("Select a slot to overwrite.");
That was my mistake - you don't need this else condition.
That's not the major problem, though, just a bit of pointless code. I don't know what the main problem is. That code works perfectly for me, with or without the Confirm GUI, and whether I used selected_slot or save_listbox_chris.SelectedIndex. The one problem I had was trying to reload a game saved with an eariler version of the code (i.e. before I'd added the Load and Confirm GUIs) which will cause a crash (What error message do you get when it crashes, by the way?). The lists and overwriting works great - I honestly can't see why it's not working for you.
Sorry this isn't more help...
I don't know either.
The error message says:
Error: Restore_game: Global script changed, cannot restore game.
That error message means that you tried restoring a savegame that was saved with an earlier version of your game.
Go into your compiled-folder and delete all the savegame-files in there. Then restart your game and save/restore. This error message shouldn't come up any longer...
That's the error I was talking about.
What dkh said should solve the crash, and starting from fresh might clear up the list bug.
EDIT: To get the name right. Sorry dkh.
Well it doesn't crash any more.Ã, It still will repeat a previously saved game.Ã,Â
But here's an interesting thing:
It repeats a previos saved game only when I type it in the textbox and the Confirm GUI appears.Ã, When I highlight a previous game from the listbox and it appears in the textbox and hit save, the Confirm GUI doesn't appear and then it overwrites it exactly as it should.Ã,Â
I don't know if that means anything, but I thought it may.
That's because overwriting without changing the name is handled by a seperate condition (if (StrComp (input, item) == 0)).
Hang on - I might have misunderstood the problem here.
Do you want it that if you type the name of an existing slot, that slot will be overwritten even if it isn't selected? 'Cause that's totally different to what I was thinking the problem was, and I reckon I know how to solve that (it's not actually a bug, just the way the code is written).
What I thought should happen is whether typed in or highlighted, and whether the listbox has less that 20 or more than 20, there would never be duplicate named saved games.
No, the way it works now is:
1. If you select a slot
save_textbox_chris 'gets' the name of the slot. If you hit 'Save' right away the slot will be overwritten with the same name. If you change the name at all, it counts as a 'new' slot name.
2. If you enter a 'new' slot name
If there are less that 20 existing savegames, a new slot will be created with the name you entered - even if a game with the same name already exists. If there are 20 existing savegames the selected slot is overwritten with the name you entered - even if a game with the same name already exists.
(SelectedIndex defaults to the top slot when the GUI opens - if you haven't been changing this, that would explain why the top game is always overwritten.)
Now, if you want to check all slots against the entered name and overwrite if there's a match, you need to turn these conditions:
if (save_listbox_chris.SelectedIndex!=-1) save_listbox_chris.GetItemText(save_listbox_chris.SelectedIndex, item);
if (StrComp (input, item) == 0) {
SaveGameSlot (savegameindex[save_listbox_chris.SelectedIndex], input);
gSavegui.Visible=false;
}
into a while loop to check input against every ListBox item, not just the selected one:
selected_slot = 0; // You can make a new int for this, if you'd rather
while (selected_slot < bg_save_idx) { // i.e. < number of items
save_listbox_chris.GetItemText(selected_slot, item);
if (StrComp (input, item) == 0) {
SaveGameSlot (savegameindex[selected_slot], input);
gSavegui.Visible=false;
return;
}
selected_slot ++;
}
(Not very thoroughly tested, but should work.)
Which will check all existing slots against the entered name. If a match is found, it'll overwrite and stop. If no match is found, it'll go on the the other conditions (save or overwrite with a new name). You'll also need to change else if (bg_save_idx<20) to if (bg_save_idx<20).
Perfect! That's exactly the way I wanted it.
I would say we could wrap this one up. I apologize that it took so long to get it to this point, and again I appreciate all the help.