Adding string variable to parser, is it possible? (SOLVED)

Started by LRH, Thu 21/01/2010 02:45:34

Previous topic - Next topic

LRH

I'm once again using the enhanced parser to make my current project. I received a lot of good help earlier from the community about how to get a string variable from the player, and I'm good with that. Now I've got a bigger problem:

Here's an example.

I ask the player what their favorite food is. I want them to be able to type in anything, so they aren't limited to any choices. They type it in, and it is stored as a variable. For the sake of example, let's say they wrote 'pizza' and the global string variable is called 'favfood'.

Now, later in the game I ask "What was your favorite food again?" I followed the instructions I was given before, but the game crashes with an error that stored variable favfood 'pizza' is not on the list of parser words. This is an issue, since obviously I cannot add every single food in the world to the parser list. Is there any way around this?

tzachs

I don't know if there's a way to add a word to the parser in run-time, but I think that in the scenario you're describing you don't have to use the parser at all...
You can just compare the string in your global variable to the string in the textbox.

Khris

Yes, you'd have to use a variable to tell AGS that instead of parsing the input, it's supposed to compare it.
You could set a bool (e.g. ask_food) to true as soon as the game reaches the point where it's supposed to ask the player for the food they typed in earlier.
Then, do this:

Code: ags
  // process user input
  if (ask_food) {
    if (input.CompareTo(fav_food) == 0) {
      // player entered the same food
      ask_food = false; // reset
    }
    else {
      Display("That's not what you told me last time...");
    }
  }
  else {
    // parse input
  }

Goldfish

if you really wanted to keep the parser thing going, why NOT find 80 or so common foods, especially listing "favourites" people around the world like...

Then parse for eg pizza instead of "whatever" pizza, and so on.

If they initially enter something insane, that is not taken into account on your uber-list, then just respond with a "REALLY? I never even HEARD of that!" or whatever.

For the sake of the effort to find a BIG list of stuff to add to the parser, imagine how cool it would be when you really have out thought a lot of players. Other than tiresome smart asses of course.

LRH

Quote from: Khris on Thu 21/01/2010 09:09:20
Yes, you'd have to use a variable to tell AGS that instead of parsing the input, it's supposed to compare it.
You could set a bool (e.g. ask_food) to true as soon as the game reaches the point where it's supposed to ask the player for the food they typed in earlier.
Then, do this:

Code: ags
  // process user input
  if (ask_food) {
    if (input.CompareTo(fav_food) == 0) {
      // player entered the same food
      ask_food = false; // reset
    }
    else {
      Display("That's not what you told me last time...");
    }
  }
  else {
    // parse input
  }


Ah, ok. I suppose this is my problem. Since the parser comes up in game whenever something is typed, it hadn't occurred to me to simply disguise a GUI textbox as the room's "parser" tricking the player into thinking it was the same thing.
Thanks for the help, I'm off to work a bit today but I'll try this out later.

@ Goldfish - That would be something, but food was just for the sake of example...
If I told you what the variable truly was, it would give away a riddle to the game I have coming out :P

Khris

You don't need a second GUI/Textbox; you simply have to handle the entered string differently depending on the "state" of the game (which is stored in variables).
As in, don't parse the user input right away. See my code.

RickJ

Here is another idea that may be of some help here.  You can emulate what the parser does by appending things to a string like this for example:

Code: ags

String Fruit;

Fruit=",";
Fruit = Fruit.Append("Apple,");
Fruit = Fruit.Append("Orange,");
Fruit = Fruit.Append("Banana,");


You can then use the String.IndexOf() function to see check the string.

Code: ags

bool  SaidFruit(String text) {
   return (String.Format(",%s," text))>-1);
}
 
if (SaidFruit("Orange")) Display("He said orange");


You could make your own parser by expanding upon this idea.   It would take the form of a couple String arrays.  One array would hold a list of categories. Eqach element of the other array would contain a word list for the corresponding category.   For example if the names of fruits were stored in element 0 of the second array then "fruit" would be stored in element 0 of the first array.    Then an "IfSaid()" function like this IfSaid("fruit", text) could be created and used.

There are other details to contend with such as case sensitivity, etc but I think this illustrates the idea.


LRH

Quote from: Khris on Thu 21/01/2010 09:09:20
Yes, you'd have to use a variable to tell AGS that instead of parsing the input, it's supposed to compare it.
You could set a bool (e.g. ask_food) to true as soon as the game reaches the point where it's supposed to ask the player for the food they typed in earlier.
Then, do this:

Code: ags
  // process user input
  if (ask_food) {
    if (input.CompareTo(fav_food) == 0) {
      // player entered the same food
      ask_food = false; // reset
    }
    else {
      Display("That's not what you told me last time...");
    }
  }
  else {
    // parse input
  }


Ahhhhh okay. I think I'm starting to get it a bit better. I REALLY appreciate all of the help I've been getting and I do apologize for not being a bit quicker to understand the code above, but I have a few questions.

With the enhanced text parser template I'm using, typing any letter immediately makes the parser's textbox visible. So what I think you're trying to say is, I don't need to make another GUI, rather I should make what's in the textbox of the parser gui be compared to my global variable, 'favfood'.  Only problem here is, pressing enter automatically parses the text, at which point the game crashes because the word for favfruit is not in the dictionary. So I guess my problem now is... how can I make it so that the textbox doesn't parse in this case? In the first instance of the player entering data, I solved this by using an "ok" button, but now that the player is in game, the "ok" button would look tacky, and the enter button causes it to parse before it can compare. At least, I think that's what is going on. Again, sorry for needed so much help on such a small subject and I can't tell you how much I appreciate the community support.

monkey0506

When you press enter AGS is calling "txtTextboxnamehere_OnActivate" (look in GlobalScript.asc for this function).

The function probably looks something like:

Code: ags
function txtTextboxnamehere_OnActivate(GUIControl *control)
{
  Parser.ParseText(control.AsTextBox.Text);
}


Just change it to look more like:

Code: ags

function txtTextboxnamehere_OnActivate(GUIControl *control)
{
  // process user input
  if (ask_food) {
    if (input.CompareTo(fav_food) == 0) {
      // player entered the same food
      ask_food = false; // reset
    }
    else {
      Display("That's not what you told me last time...");
    }
  }
  else {
    Parser.ParseText(control.AsTextBox.Text);
  }
}


But there's no reason why parsing an unknown word should be crashing the game. That's what Parser.SaidUnknownWord is for isn't it??

LRH

#9
Funny enough there wasn't any code under function txtParser_OnActivate(GUIControl *control)

So I just added the code from above, now pressing enter doesn't parse the text, so until I delete it, which I don't want to do, it's broken, and I'm having a heck of a time figuring out how it all worked before if no code is here...

LRH


tzachs

#11
It did help...
Open your globalscript.asc, and search for a function called interface_click.
In there you'll see the two first lines:
Code: ags

input = txtParser.Text; // gets whatever was typed and stores it as the 'input' variable
  gParser.Visible = false; //Turns the GUI off.

After those lines the input variable will hold the text. There you should put if (ask_food) bit and cut&paste the rest of the function into the else bit.
Something like this:
Code: ags

// process user input
  if (ask_food) {
    if (input.CompareTo(fav_food) == 0) {
      // player entered the same food
      ask_food = false; // reset
    }
    else {
      Display("That's not what you told me last time...");
    }
  }
  else {

    //----------------------------------------------------------
    //THIS IS THE REST OF THE FUNCTION COPIED&PASTED
    //-----------------------------------------------------------

    //Our complex "it" feature.
  if (usedIt == 0) { //this just fixes a crash if the very first command contains "it".
    itWord = "a";
    usedIt = 1;
    }
  int result = input.Contains(" it");
  if (result == -1) { //if the players input does not contain "it"...
    int i = input.Length -1;
    while (i>=0){
      if (input.Chars[i]==' ') //...the game finds out where the last SPACE is, and...
      {
        itWord = input.Substring(i + 1, input.Length -(i+1)); //...the last word is saved as the 'itWord' String.
      }
      i--; 
  }}
  if (result != -1) { //But, if it DOES contain "it"...
    input = input.AppendChar(' ');
    input = input.Append(itWord); //...itWord is added. This way you can write "look apple", then "take it". Neat, huh? :)
}

  Parser.ParseText(input); //parses the 'input' variable through our list of known words
  
//Place all global parser commands here! :)
  if (Parser.Said("quit [game]")) { QuitGame(1); }
	else if (Parser.Said("save [game]")) { SaveGameDialog(); }
	else if (Parser.Said("load [game]")) { RestoreGameDialog();}
	else if (Parser.Said("restart [game]")) { gRestartgui.Visible= true; Mouse.Mode= eModePointer;}
  else if (Parser.SaidUnknownWord()) { // if an unknown word has been said
  Display("Please use another word for '%s'.", Parser.SaidUnknownWord()); // %s will be replaced with the unknown word and printed on screen
  }
  else if (Parser.Said("inv")) { ShowInv(); } //show inventory
  
  else if (Parser.Said("look key") && (player.InventoryQuantity[iKey.ID])) { 
    ShowInvCloseup(42, "This is the ugliest key you have ever seen."); //This shows a closeup of the inventory item Key when looked at.
                                                        // 42 is the number of the key sprite (not the meaning of life!).
  }
  
	else { //if none of the previous commands matched
  CallRoomScript(1); }// After checking the global script, the parser will go to the script of the current room. Add room-specific commands there!
}
  }

LRH

THANK YOU!!!!!!!!

Finally, it works. Thank you so much.

SMF spam blocked by CleanTalk