Help with a trigger for a Y/N GUI for overwriting existing savegames?

Started by Fitz, Mon 08/10/2012 12:31:30

Previous topic - Next topic

Fitz

I introduced a Yes/No GUI popping up when you try to overwrite an existing savegame. I disabled the feature that fills the textbox with the first savegame's name, so that you can enter a new one each time - but if you click on one of the list, the game asks you if you're sure you want to overwrite it. Got all of it figured out and it seemed to works like a charm - except for one thing that I didn't even notice at first. The script (the part in bold letters) that I used as a trigger:

if (txtNewSaveName.Text == lstSaveGamesList.Items[lstSaveGamesList.SelectedIndex])
    {
    gOverwriteYN.Visible = true;
    }

...is not right. It recognizes if the name of the new same is identical with the selected savegame - even if I try to modify it and revert to previous state (say, delete a letter and then put it back). But I need it to recognize ALL the savegame items, not just the one currently highlighted -- and I can't seem to find the right code for that.

Khris

You need to iterate through all entries for that:

Code: ags
  int i;
  bool match;
  while (i < lstSaveGamesList.ItemCount) {
    if (lstSaveGamesList.Items[i] == txtNewSaveName.Text) match = true;
    i++;
  }
  if (match) gOverwriteYN.Visible = true;

Fitz

OK, I'm trying to get my head around how to incorporate that into my code - and failing ;) Here's how it looks:

Code: ags

if (the condition that triggers the Y/N gui) {
  gOverwriteYN.Visible = true;
  gSaveGame.Clickable = false;}

else {
  int gameSlotToSaveInto = lstSaveGamesList.ItemCount + 1;
  int i = 0;
  while (i < lstSaveGamesList.ItemCount)
  {
    if (lstSaveGamesList.Items[i] == txtNewSaveName.Text)
    {
      gameSlotToSaveInto = lstSaveGamesList.SaveGameSlots[i];
    }
    i++;
  }
  SaveGameSlot(gameSlotToSaveInto, txtNewSaveName.Text);
  close_save_game_dialog();
  gPanel.Visible = false;
  if (cGray == player) {
    gIconbar.Visible = true;}
  mouse.UseDefaultGraphic();
}


Everything after "else" is standard AGS SaveGame gui. The script behind the "Yes" button in the Y/N gui is an exact copy of that. Now, how do I set up the condition for Y/N pop-up without doubling anything.

Khris

Here's the cleanest way:
Code: ags
void SaveGame() {
  // original save button code in here
}

// save button code
  int i;
  bool match;
  while (i < lstSaveGamesList.ItemCount) {
    if (lstSaveGamesList.Items[i] == txtNewSaveName.Text) match = true;
      i++;
  }
  if (match) {
    gOverwriteYN.Visible = true;
    gSaveGame.Clickable = false;
  }
  else SaveGame();
}

// overwrite? yes button code
  gOverwriteYN.Visible = false;
  SaveGame();

Fitz

Nope, still can't get it to work. One time it added a blank one (no name) and another time it overwrote something without asking. Maybe I'm doing it wrong -- because I simply don't always get what's happening there and what and how exactly detects that the entered name matches the name of the items already there. So let's just drop that. Asking whether to overwrite the checked one is good enough. But there's still one bug my in my code: when there are no saves, you can't save (I'd noticed that only after I tried deleting them all to check the Erase Savegame -- which works fine). It crashed, pointing me to the line

if (txtNewSaveName.Text == lstSaveGamesList.Items[lstSaveGamesList.SelectedIndex]) {

probably because the list is empty and there is no selection. So I could probably use a condition checking if there are any items in the list (that I'd && to the string quoted right above)? Or something else?

Khris

The condition you're looking for is lstSaveGamesList.ItemCount > 0.
Put it directly behind the if though, otherwise it won't stop the crash.

You shouldn't give up on the other issue though.
Provided you're using the original default game code inside SaveGame(), what I posted should work just fine.

Fitz

That one worked perfectly -- and it's so neat and simple. Can't believe I overlooked that option. But I'm currently pretty much a zombie -- not sleeping very well, and my eyes feel like they're about to pop. But I will try to get back to the problem. I just need to clear my head.

If you'd like to look at the whole thing, here are the two main components:

1. The SAVE button in the gSaveGame:

Code: AGS

function btnSaveGame_OnClick(GUIControl *control, MouseButton button)
{
  int gameSlotToSaveInto = lstSaveGamesList.ItemCount + 1;
  int i = 0;

if (lstSaveGamesList.ItemCount > 0 && txtNewSaveName.Text == lstSaveGamesList.Items[lstSaveGamesList.SelectedIndex]) {
  gOverwriteYN.Visible = true;
  gSaveGame.Clickable = false;}

else {
  while (i < lstSaveGamesList.ItemCount)
  {
    if (lstSaveGamesList.Items[i] == txtNewSaveName.Text)
    {
      gameSlotToSaveInto = lstSaveGamesList.SaveGameSlots[i];
    }
    i++;
  }
  SaveGameSlot(gameSlotToSaveInto, txtNewSaveName.Text);
  close_save_game_dialog();
  gPanel.Visible = false;
  if (cGray == player) {
    gIconbar.Visible = true;}
  mouse.UseDefaultGraphic();
  }
}


2. The OK button in the Y/N pop-up gui (which is an almost exact copy of the part after "else" above):

Code: AGS

function Button12_OnClick(GUIControl *control, MouseButton button)
{
  int gameSlotToSaveInto = lstSaveGamesList.ItemCount + 1;
  int i = 0;
  while (i < lstSaveGamesList.ItemCount)
  {
    if (lstSaveGamesList.Items[i] == txtNewSaveName.Text)
    {
      gameSlotToSaveInto = lstSaveGamesList.SaveGameSlots[i];
    }
    i++;
  }
  SaveGameSlot(gameSlotToSaveInto, txtNewSaveName.Text);
  gSaveGame.Clickable = true;
  close_save_game_dialog();
  gOverwriteYN.Visible = false;
  gPanel.Visible = false;
  if (cGray == player) {
    gIconbar.Visible = true;}
  mouse.UseDefaultGraphic();
}


I intentionally put the i++ in the sequences that save the game (the one after "else" and the "OK" button), not in the preliminary code (or whatever you want to call the part before the if's and else's). That's because there's a NO button in the Y/N gui -- and the game isn't supposed to be saved when it's pressed. If nothing happens, there is no reason for "i" to change value. I did try it, and the i++ did give me trouble if placed too early.
In its current form the whole thing seems to work just right -- so if you could just weave the extra code into that without re-arranging it, so I could just copy the whole thing in the right place, it'd be the easiest and safest way to make sure it'll work.

Thanks for bearing with me. If you still feel like helping me out, we have as much time as we need on this, I'm in no hurry. Before the game is out -- and it IS almost done -- I *just* have to translate over 5000 lines of dialogue for "Gray" from English to my native language. So yeah, there's PLENTY of time :)

Fitz

Gave up on it, eventually, and left it the way you see in the post right above. Works fine -- with just one little "but". By default, the textbox for entering the savegame name is blank - so you can make a savegame with no name. Again, no big deal - but it'd look nicer if I could have a pop-up urging the player to type something if no text has been entered. Is there some code for detecting whether or not any text was entered? If it's something more complex, where do I put it inside the code (check the post right above to see what it looks like).

geork

Sure, you could check whether the String returned is blank before you pop up the Y/N GUI:
Code: AGS
if (lstSaveGamesList.ItemCount > 0 && txtNewSaveName.Text == lstSaveGamesList.Items[lstSaveGamesList.SelectedIndex]) {
  if(txtNewSaveName.Text == "") Display("fill in save name please (or some-such)");//Start New Bit - check whether the string is ""
  else{
    gOverwriteYN.Visible = true;
    gSaveGame.Clickable = false; 
  } //End new bit
}//I've done stuff to the brackets because I'm OCD about layout, change back if you want :P

That should hopefully work. You cooould avoid an empty string with multiple spaces by changing this line:
Code: AGS
if(txtNewSaveName.Text.Truncate(1) == " ") Display("fill in save name please (or some-such)");//important it's " " not ""

Although that's being VERY nitpicky

Both are untested, but should work fine :)

Fitz

Thanks :) I'll try both things out later today. That second bit of code might come in VERY handy, because I usually AM very nitpicky about my own work :]

I will get back to you once I've tested it.

EDIT/UPDATE

Tried it - but instead of making it DISPLAY the message, I made the textbox itself show it.

if (gSaveGame.Visible == true  && txtNewSaveName.Text == ""||gSaveGame.Visible == true  && txtNewSaveName.Text == "Enter a save name") {
  txtNewSaveName.Text = "Enter a save name";}

So now if the textbox is blank upon trying to save the game, it is filled with "Enter a save name" - and to avoid saving the game AS "Enter a save name", as you see I added a restriction for that, too.

I also got a little creative with rep_exec_always. I put two things there:

Code: ags
if (gSaveGame.Visible == true && lstSaveGamesList.ItemCount > 0  && txtNewSaveName.Text == " ") {
  txtNewSaveName.Text = "Enter a save name";}


...which automatically fills the textbox with "Enter a save name" if only a space is entered.

And...

Code: ags
if (gSaveGame.Visible == true && lstSaveGamesList.ItemCount > 0  && txtNewSaveName.Text == "Enter a save nam") {
  txtNewSaveName.Text = "";}


...which clears the whole textbox if the last letter from "Enter a save name" is removed -- since the intuitive thing to do when an unwanted text appears is to manually remove it (via backspace). It's not failsafe, since you can still ADD text to the string and save it. It'd be cool to have a way to restrict a name merely CONTAINING the string "Enter a save name" but again, it's not a serious issue, I'm just curious and trying to learn. Haven't tried the second piece of code you gave me -- which may be the answer to that.

EDIT:

Or better yet, it could remove the "Enter a save name" and reduce it to "" if ANY key is pressed -- as in IsKeyPressed() - but what do I put in those brackets? I tried putting an extra condition:

Code: ags
if ((keycode >= 65) && (keycode <= 90)) {


to the Rep_Exec_Always - but keycodes are defined later on and I'm not sure if I can move Rep_Exec to a different position without messing something up. Putting the above bit of code in the keycode section, in turn, does nothing: nothing happens when a key is pressed.

Again, just playing around, trying things out, it doesn't HAVE TO be in the game :)

geork

Sure, whet you could do is check whether the string is longer than the original, and then just substring the last letter, switching a boolean value in the process to make sure nothing is re-substringed, something like:

At the top of the script
Code: AGS
bool switch;
String message;


then in game_start:
Code: AGS
message = "Enter a save name"; //this'll allow you to change the message whenever you want without mucking up future code


then when making the gSaveGame GUI visible:
Code: AGS
switch = false;
txtNewSaveName.Text = message;
gSaveGame.Visible = true //etc etc


The in repeatedly_execute_always():
Code: AGS
//to test whether anything has changed in the text box:
if(gSaveGame.Visible == true && lstSaveGamesList.ItemCount > 0  && txtNewSaveName.Text.Length != messsage.Length && !switch){ //17 is how long "Enter a save name" is, change it as required...also "!switch" is the same as "switch == false"
  switch = true; //if the player writes anything longer than 17 characters, we don't want THAT to substring, so change the value of switch
  if(txtNewSaveName.Text.Length > messsage.Length){ //if the player has typed a character
    String s = txtNewSaveName.Text.Substring(messsage.Length,1); //remember, substring starts from length - 1
    txtNewSaveName.Text = s; //so it'll be the character the player types
  }
  else{ //if the player has used backspace
    txtNewSaveName.Text = "";
  }
}
if (gSaveGame.Visible == true && lstSaveGamesList.ItemCount > 0  && (txtNewSaveName.Text == " ") {//this check will prevent space being pressed at first
  switch = false; //switch this back so further checks can be made
  txtNewSaveName.Text = message;
}


Keep the restriction you already had and bingo! This has been tested, so should work here to. There's probably more efficient ways of doing it, but that's my solution - hope it's what you were looking for :)

SMF spam blocked by CleanTalk