Help with getting char to say a random thing, from a list of possibilities.

Started by markbilly, Tue 22/02/2011 22:03:07

Previous topic - Next topic

markbilly

Basically, I have a list of questions of the which a character will say one of them at random.

I was thinking of setting up a load of strings at the beginning of the script, which are obviously the possible questions and naming them so:

Qnm - where n is the category number and m the question number within that category.

i.e.
Code: ags

String Q00 = "How are you?";
String Q01 = "Do you like the weather outside?";
...
String Q21 = "What are your hobbies?";


The problem starts with getting that into the .Say() function. I could have:
Code: ags

n = Random(5); //There are 6 categories
m = Random(2); //There are 3 questions in each category


How do I then get the n and m I have defined to relate to the Strings?

I'm a lousy coder, I hope someone can help!
Thanks :)


EDIT:

I found this online:
Code: ags

#include <stdio.h>
#include <conio.h>
void main() {
  clrscr();
  char arr[3][12]= { "Rose", "India", "technologies" };
  printf("Array of String is = %s,%s,%s\n", arr[0], arr[1], arr[2]);
  getch();
}


It is some direction for setting up an array of Strings, which I didn't think you could do. So, I suppose the question now is: How do I implement this in AGS, or is there an better alternative?

Thanks again.
 

Calin Leafshade

#1

an array of strings is probably best.

something like this would do it:

Code: ags

  String strings[7];
  strings[0] = "this is in category one";
  strings[1] = "this is also in cat one";
  strings[2] = "And this.";
  strings[3] = "cat 2 starts here";
  strings[4] = "omgosh more cat 2!";
  strings[5] = "Now we're onto cat 3";
  strings[6] = "and another";

String GetRandomString(int category){
  
  int offset;
  int numberofoptions;
  if (category = 1) {
    offset = 0; //where the category starts;
    numberofoptions = 3; // how many options in the category

  }
  else if (category = 2) {
    offset = 3;
    numberofoptions = 2;

  }
  else if (category = 3) {
    offset = 5;
    numberofoptions = 2;

  }
  
  int ran = Random(numberofoptions) + offset;
  
  return strings[ran];
  
}

[/s]

Wait scratch that. Are category and question *both* random?

in that case you could just use:

Code: ags

  String strings[7];
  strings[0] = "this is in category one";
  strings[1] = "this is also in cat one";
  strings[2] = "And this.";
  strings[3] = "cat 2 starts here";
  strings[4] = "omgosh more cat 2!";
  strings[5] = "Now we're onto cat 3";
  strings[6] = "and another";

String GetRandomString(){

   return strings[Random(6)];
}


Khris

To elaborate a bit:
markbilly, you're trying to get from a variable's value to another variable's name. This isn't possible in AGS. If you need a group of variables, you have to use an array; that way you can translate a value into the index of the array, the only way to avoid long if-else if blocks.

Now while AGS doesn't support multidimensional arrays, you can cheat by using a struct:

Code: ags
// header
struct str_cat {
  String option[10];
};

// script
str_cat category[10];


This creates 100 variables that can be accessed like this:
Code: ags
  category[3].option[5] = "Whatever";


If you need more dimensions, you can always calculate the index number, similar to how you set up your example Strings, only you'd declare String Q[100], then use category*10 + option to get the index number.

AGS uses the same system to turn a color consisting of an R, G and B value into a single number.

markbilly

Khris, your solution sounds very simple! I'll have a go at doing that. One quick question, though: the program needs to know what category and question it is that is chosen at random. The game basically scores you on how well you match your answers, so how can I access the value of the two elements of the chosen question?

P.S. Don't worry, Calin, I learned a lot from your examples! :)
 

Khris

Like this:
Code: ags
  cat = Random(9);
  opt = Random(9);
  cHost.Say(category[cat].option[opt]);

  // later
  if (opt == chosen_answer) ...  // or something to that effect


cat and opt should be global variables so that they retain their values after the function in which the question is asked has finished.


markbilly

Hope I don't get pounced on from posting here again but there is no point starting a new thread...

Anyway having done the struct, I have set up a list of questions using:

Code: ags

category[3].option[5] = "Whatever";


But I get a parse error saying "unexpected 'category'" I'm a little confused.

Also, this line:
Code: ags

cHost.Say(category[cat].option[opt]);


Produces error: "category is not an array"
 

Khris

We need to see more of your code; where did you put those lines, how did you declare category, etc.

markbilly

Sorry, I was too hasty. I found a better way using ordinary arrays in the end. It makes the whole thing more flexible.

Thanks for the help. I'm sure I'll get stuck again... ;)

EDIT: I got stuck again, on a separate issue but it may be related:

Code: ags

while (gov_hp && opp_hp != 0)
{
  
  //ask question
  ced.Say(GetRandomString());

  //update dialog with replies
  danswer.SetOptionState(current_question+1, eOptionOn); //correct response
  danswer.SetOptionState(Random(29), eOptionOn); //other random option
  
  //reply
  danswer.Start();
}


The dialog won't start. It just loops round ignoring it. I tried taking the loop out and it still ignores it.

Thanks again.
 

Khris

If a dialog won't start, it probably still has all its options turned off (due to them having been turned off using off forever).
What happens if you check for the option being on?

Code: ags
while (gov_hp && opp_hp != 0)
{
  
  //ask question
  ced.Say(GetRandomString());

  //update dialog with replies
  danswer.SetOptionState(current_question+1, eOptionOn); //correct response
  danswer.SetOptionState(Random(29), eOptionOn); //other random option

  // debug
  if (danswer.GetOptionState(current_question+1) == eOptionOn) Display("That's not the error.");
  
  //reply
  danswer.Start();
}


There's also an option somewhere to not display a dialog if there's only one option left.

markbilly

That's not the error, apparently.

I'm really confused by this. I can get it to enter an invalid dialog option number, which causes the game to error, so it is obviously updating the dialog options. It seems it just won't start the dialog going.

I've found the problem: IT'S THE WHILE-LOOP. When I take that out it works, which is annoying because I need it there.
 

Khris

So in other words, the condition is never true?

It shouldn't matter that you wrote the condition like that in this case, though it should probably read while (gov_hp != 0 && opp_hp != 0).
While it's fine with testing for being not zero, you can't translate the English sentence "while gov_hp and opp_hp are (not) some value" directly in general; usually you have to state each condition in full.

But, like I said, in the special case of testing for "!= 0", it should actually work.

In fact, you'll get the same result using while (gov_hp && opp_hp) or even while (gov_hp * opp_hp).

The problem seems to be that at least one of the variables is 0 though, obviously; double-check they are set correctly.
Did you by any chance declare them in the script header? That would explain it.

markbilly

I can't see how that could be the problem, I've tried it both ways. Besides, it runs everything else in the loop, up until the dialog and it just skips back to the top of the loop at that point...
 

Khris

No it doesn't.
Commands aren't occasionally skipped.

If you're positive that this line
Code: ags
ced.Say(GetRandomString());

is executed, then it follows that the dialog has exactly one option turned on, set to not being said.
This option is chosen automatically, then the dialog stops. All this will not be happening visibly though, giving the impression that the dialog wasn't started in the first place.

More than one option, and you'd get to choose one, zero, and you'd get an error message.
You can easily test this by adding a line directly after @S. Just put "player: hello" or something there, and it should appear when the dialog gets started.


Seriously, if the two options are an error on your part and AGS randomly ignoring commands at will, what is more likely...?

markbilly

It definitely runs all of the commands in the while loop up until the Dialog.Start, I've done every check I can think of.

I reckon, because AGS is starting a dialog, it wants to wait to start it until the loop is over.
 

Khris

Right, but afaik in that case the dialog commands would quickly fill up the queue and you'd get an error message.

I tested this a second ago and got this error immediately:

RunDialog: Cannot queue action, post-script queue full

Further testing reveals that AGS can only store 6 or 7 dialogs calls in the queue.
My best guess at this time is that the while loop runs through several iterations, each time queuing a dialog that does nothing, then exits. The queue is processed, but the dialog does nothing.

Did you try adding a "player: hello" after @S?


Or better, you say you're positive the while loop is running; how often does ced say the random string?

markbilly

ced just keeps saying the RandomString() until an error*, because the opp_hp and gov_hp variables are only changed in the dialog.

Tried adding "player: hello" in @S, to no avail.

*RunDialog: Cannot queue action, post-script queue full
 

monkey0506

You can't call Dialog.Start from within a while loop because it's a delayed function. Dialog.Start will be queued but never executed until the end of the entire game loop (not the end of the while loop iteration).

Edit: I'm not entirely sure where your variables you're checking in your while loop's condition are updated at, but you might want to consider how your dialog is organized anyway if you're needing it to be dependent on them. You might want to move some of the logic directly into the dialog script.

SMF spam blocked by CleanTalk