timer and talking (SOLVED)

Started by Matti, Sat 26/01/2008 19:50:57

Previous topic - Next topic

Matti

I want a guy in my adventure to permanently talk to himself - without any interaction of the main character or someone/something else. And I want him to say something randomly chosen from several sentences. And it would be cool, if the time between his talkings would be a random number of seconds too. What is the best way to do this and how do I create and use a timer variable (I didn't use variables yet)?

Matti

And how do I make a variable that is set to a random value when - let's say - entering a room..?

monkey0506

#2
Okay, the easiest way to go about this without having to get into the AGS 2.72 or 3.0 question would be to just use on_event to by-pass the room event handlers, so here we go:

Code: ags
// top of room script
String HoboLines[MAX_LINES]; // replace MAX_LINES with the number of different sentences the "hobo" will say
// I just imagine some guy walking around aimlessly talking to himself to be a hobo...;)
int HoboTimer = -1; // the timer we'll use
int HoboLine = -1; // the line (sentence) for the hobo to say
Overlay* HoboSpeechOverlay; // the screen overlay used to make the hobo talk in the background

function on_event(EventType event, int data) {
  if (event == eEventEnterRoomBeforeFadein) {
    HoboLines[0] = "What're you lookin' at?"; // replace these with your actual sentences
    HoboLines[1] = "They're after my lucky charms...damn kids.";
    HoboLines[2] = "Talking to myself is a sign of madness, and I'm pissed off!";
    // etc.
    HoboTimer = Random(GetGameSpeed() * 3) + GetGameSpeed(); // wait anywhere from 1 to 4 seconds after entering room before talking
  }
}

function repeatedly_execute_always() {
  if (HoboTimer) { // this is the same as "HoboTimer != 0" meaning the timer is NOT equal to 0
    if ((HoboSpeechOverlay == null) || (!HoboSpeechOverlay.Valid)) HoboTimer--; // decrease our timer by 1 if the hobo isn't speaking yet
                                                                                // or if he's done saying the last sentence
    return; // and abort this function
  }
  // the timer has expired, make the hobo say some random sentence
  HoboLine = Random(MAX_LINES - 1); // Random(X) returns a value 0-X inclusive and the maximum index of our array is MAX_LINES - 1
                                    // so we need to be sure we're in this range
  HoboSpeechOverlay = cHobo.SayBackground(HoboLines[HoboLine]);
  HoboTimer = Random(GetGameSpeed() * 3); // wait 0 to 3 seconds after saying this sentence before saying the next one
}


That actually answers both posts I believe. If you have any questions about this I'd be glad to answer them for you.

Matti

Wow. Thanks much. Works perfectly.
Isn't a hobo though. It's just a bored and annoyed guy in a bar. But I'll use it too for two persons in a permanent discussion, which would have been my next question here.
Thanks again..

monkey0506

I'm glad to hear you got it working so quickly. To be honest as you're a new member here I didn't get my hopes too high that you would be able to properly implement my code, but it seems you've done it. A lot of our newer users aren't well adjusted to scripting and frequently fail to properly interpret things like MAX_LINES.

Like I said though, you've gotten it working which is great. One entry in the manual I wanted to be sure you read though is the entry on arrays. Arrays can be a very intimidating prospect for those new to scripting and/or AGS. If you're familiar with the concept that's wonderful but I just wanted to help increase your understanding of how the code all works and fits together. To be honest though, it wasn't really necessary per se to use an array, you could have used a series of if-else statements, but I just find the array route easier.

Oh, and as for the hobo bit, it was just the first thing that popped into my mind. ;)

Matti

Years ago I programmed a bit with Pascal and Basic, so scripting in general isn't THAT new to me.
Now I have the problem that I can't get this script working for TWO characters in the same room. I copied the (necessary) script and dublicated the variables but it won't work for the 2nd person. Don't know why..

-> I need that for the background-discussion I mentioned..

monkey0506

#6
Can you post the current code?

Although if you're wanting a background conversation, you might try a variation like this:

Code: ags
// room script
String FrankLines[MAX_LINES];
String BobLines[MAX_LINES];
Character* Initiator[MAX_LINES]; // the 'initiator' of the round of background dialog; the Character who speaks first
int timer = -1;
int line = -1;
Overlay* FrankSpeechOverlay;
Overlay* BobSpeechOverlay;

function on_event(EventType event, int data) {
  if (event == eEventEnterRoomBeforeFadein) {
    FrankLines[0] = "What're you lookin' at?";
    BobLines[0] = "Hard to say with me lazy eye, innit?";
    Initiator[0] = cFrank;
    BobLines[1] = "They're after me lucky charms...damn kids.";
    FrankLines[1] = "Usually I be the one chasin' after the kiddies...";
    Initiator[1] = cBob;
    FrankLines[2] = "Talking to myself is a sign of madness, and I'm pissed off!";
    BobLines[2] = "Carry on then.";
    Initiator[2] = cFrank;
    // etc.
    timer = Random(GetGameSpeed() * 3) + GetGameSpeed();
  }
}

function repeatedly_execute_always() {
  if ((FrankSpeechOverlay != null) && (!FrankSpeechOverlay.Valid)) FrankSpeechOverlay = null; // simplifies our checks later ;)
  if ((BobSpeechOverlay != null) && (!BobSpeechOverlay.Valid)) BobSpeechOverlay = null;
  if (timer) {
    if (line != -1) {
      Character* init = Initiator[line];
      if ((init == cFrank) && (FrankSpeechOverlay == null)) {
        BobSpeechOverlay = cBob.SayBackground(BobLines[line]);
        line = -1;
      }
      else if ((init == cBob) && (BobSpeechOverlay == null)) {
        FrankSpeechOverlay = cFrank.SayBackground(FrankLines[line]);
        line = -1;
      }
    }
    else if ((FrankSpeechOverlay == null) && (BobSpeechOverlay == null)) timer--;
  }
  // the timer has expired
  line = Random(MAX_LINES - 1);
  if (Initiator[line] == cFrank) FrankSpeechOverlay = cFrank.SayBackground(FrankLines[line]);
  else BobSpeechOverlay = cBob.SayBackground(BobLines[line]);
  timer = Random(GetGameSpeed() * 3);
}


Using this code Frank would always speak first, then Bob would respond. If you want them to be able to switch off, you could probably just use some variable to store the current speaker...or speech initiator, then when his Overlay has expired, have the other Character respond.

I've updated the code to allow for either character to initiate the sub-dialog. However I haven't tested it, so I might have messed something up a bit there. ;)

Matti

#7
An error message occures: "line 32: FrankSpeechOverlay is not an array":

      if ((init == cFrank) && (FrankSpeechOverlay[line] == null)) {

Matti

Just got another problem. It's not that big, but a bit unnecessary: It's a large scrollable room and when the discussing characters are out of sight, their speech is still shown at the edge of the screen. Would be better if the speech wouldn't appear in this case.

Khris

Remove the [line] part. (In both occurrences.)
To address the second problem compare cFrank.x against GetViewPortX().

Matti

Okay, no error message now.
But Frank says his sentences VERY speedy one after the other while Bob simultaniously gets stuck on his [1] Sentence: ...damn kids." I even can't stop the game because the menu is blocked (which happens when someone speaks).

Matti

#11
Seems like only the initiator says his thing and there's no response (and never a pause).

But I think this isn't exactly what I want anyway. My original idea was to have a person talking and talking like "..and then happenend.. ..and did you know that...." and so on. The other person randomly answers like: "...okay..  ..well.. ..I understand..." Just parts of an unimportant background discussion.

The idea was just to fill the room with life.. (it's a bar) and that the one person is a tattletale (or how it's called).

monkey0506

#12
Quote from: KhrisMUC on Sun 27/01/2008 16:08:21Remove the [line] part. (In both occurrences.)

Sorry 'bout that. Thanks Khris. Like I said:

Quote from: monkey_05_06 on Sat 26/01/2008 23:56:05I haven't tested it, so I might have messed something up a bit there. ;)

:=

However, the menu shouldn't be blocked by background speech. Background speech should allow all other interactions to carry on normally.

So then...let's see if we can get something working here like this:

Code: ags
String FrankLines[FRANK_MAX_LINES];
String BobLines[BOB_MAX_LINES];
int FrankTimer = -1;
int BobTimer = -1;
Overlay* FrankSpeechOverlay;
Overlay* BobSpeechOverlay;

function on_event(EventType event, int data) {
  if (event == eEventEnterRoomBeforeFadein) {
    int speed = GetGameSpeed();
    FrankTimer = Random(speed * 2) + speed;
    FrankLines[0] = "...it all started when...";
    FrankLines[1] = "...and then after that happened...";
    FrankLines[2] = "...and did you know that...";
    // etc.
    BobTimer = Random(speed * 2) + speed;
    BobLines[0] = "...okay...";
    BobLines[1] = "...well...";
    BobLines[2] = "...I understand...";
    // etc.
  }
}

function repeatedly_execute_always() {
  int speed = GetGameSpeed();
  if (FrankTimer) FrankTimer--;
  else {
    if ((cFrank.x >= GetViewportX()) && (cFrank.x <= (GetViewportX() + System.ViewportWidth))
      FrankSpeechOverlay = cFrank.SayBackground(FrankLines[Random(FRANK_MAX_LINES - 1)]);
    FrankTimer = Random(speed * 2) + speed;
  }
  if (BobTimer) BobTimer--;
  else {
    if ((cBob.x >= GetViewportX()) && (cBob.x <= (GetViewportX() + System.ViewportWidth))
      BobSpeechOverlay = cBob.SayBackground(BobLines[Random(BOB_MAX_LINES - 1)]);
    BobTimer = Random(speed * 2) + speed;
  }
}


As for the speech appearing at the edge of the screen....this is all getting to be a bit complicated really. The easiest method would probably be to just check that the Character is actually shown on the screen (which I've now done). Hopefully this should get the code working the way it was intended. :o

I've also modified the timers so that it now waits at least one second, but no more than three between items. Bob is somewhat rude and may interrupt Frank at some points, but they should both be capable of talking at the same time if it doesn't bother you. ;)

Matti

Okay, thank you you for your patience and your coding. It works just the way it was supposed to.
The only thing is, that the menubuttons are blocked for half a second or so everytime a sentence starts, so they're somehow blinking during the discussion. But nevermind, that doesn't bother me too much. Thanks again..

SMF spam blocked by CleanTalk