Implementing a lengthy background dialog - redux

Started by Secret Fawful, Fri 14/12/2012 04:56:32

Previous topic - Next topic

Secret Fawful

All right, so I followed a similar topic from November on this subject, but that led me nowhere. I came to the conclusion I'm using this code all wrong, but I've used it the only two ways I can think of and it's still not working correctly. I'm wanting two characters or more to hold a continuous, non-blocking conversation in the background that starts once a dialog ends. Basically, I want to be able to start up such a dialogue from any point. Then if I leave and come back to the room, I want the dialogue to be running again. To accomplish this, I, of course, put the dialogue under repeatedly execute. Currently I was giving one of the characters a dummy inventory item, and then later I would take it away when I no longer wanted this conversation to happen in that room anymore.

Here is my code in the end of the dialog:

Code: AGS
cCharJack.Walk(83, 125, eBlock, eWalkableAreas);
 SetTimer(1,0);
 cCharJack.HasInventory(iInvDummy);


And then under Rep_Exec in the room itself-

Code: AGS
function room_RepExec()
{
  if (cCharJack.HasInventory(iInvDummy)){
  if(IsTimerExpired(1))
  {
    if(turn == 0)
    {
      cCharJack.SayBackground("You pompous @#%$!, just who do you think you are?");
      cRangSlim.SayBackground("I'm not going to sit here and watch you abuse your power.");
      cCharJack.SayBackground("Abuse my POWER! Huff! Huff!");
      cCharJack.SayBackground("You're lucky I don't split your skull!");
      cRangSlim.SayBackground("I've fought better men than you!");
      cCharJack.SayBackground("Who? The elderly?");
      cRangSlim.SayBackground("You are elderly! I can hear your dentures clattering!");
      cCharJack.SayBackground("Just who do you think you are, you %$@!?");
      cRangSlim.SayBackground("Don't you know who I am? I'm Steve Dedman!");
      cCharJack.SayBackground("Oh! Some puffed-up TV stooge, eh!?");
      cRangSlim.SayBackground("What did you call me, you big windbag!?");
      cCharJack.SayBackground("Windbag!?");
      SetTimer(1, 280);
    }
    else if(turn == 1)
    {    //etc etc.
      SetTimer(1, 150);
    }
    turn ++; //this is universal to all instances of dialog, so put here
  }
}
}


However, currently, the background dialogue will not play at all unless I remove the Inventory requirements, and then it will only play the final two pieces of dialogue, and at the same time. I want each piece of dialogue to play one after the other, and I want the characters to say them while animating. They do none of this. I know I'm horribly screwing this code up, so....what do I need to do to make this work? Because I can't find anything else on this. I'm honestly embarrassed to even ask because I know I'm doing this very, very wrong.

Slasher

#1
At the moment, Without looking any further than this part:

Code: AGS
 cCharJack.Walk(83, 125, eBlock, eWalkableAreas);
 SetTimer(1,0);
 cCharJack.HasInventory(iInvDummy);


Should be:

Code: AGS
 cCharJack.Walk(83, 125, eBlock, eWalkableAreas);
 SetTimer(1,0);
 cCharJack.AddInventory(iInvDummy); // Gives player iInvDummy which sets off Rep Exec events
 // OR
 cCharJack.LoseInventory(iInvDummy); //Takes away player iInvDummy 

Snarky

Beyond that, you can't just write a sequence of SayBackground statements, because they're (obviously) not blocking, and so they'll all be executed instantly, with the effect that only the last line will actually be displayed. Instead, use SSH's QueueBGSpeech module to do the conversation.

Secret Fawful

#3
Damn it, I can't believe I made that mistake on the inventory code.

As far as SSH's module, I've spent an hour trying to update the code on it, because it gives all sorts of errors now, and I'm still getting errors on it.

Code: AGS
 // Main script for module 'QueueSpeech'
queuespeech_t squeue;

function game_start () {
  squeue.insert=0;
  squeue.say=0;
  squeue.ol=null;
  squeue.stop_talk=0;
  squeue.prev_char=null;
  squeue.channel=-1;
}

function qDisplaySpeechSubtitled(Character *CharID, const string message, const string subtitle) {
   int i = squeue.insert % SPEECH_QUEUE_SIZE;

   squeue.s[i]=message;
   squeue.st[i]=subtitle;
   squeue.c[i]=CharID;
   squeue.insert++;
}

function qDisplaySpeech(Character *CharID, const string message) {
   qDisplaySpeechSubtitled(CharID, message, "");
}

function qSubtitleSetup(int y, int font, int colour) {
  squeue.subtitle_col=colour;
  squeue.subtitle_font=font;
  squeue.subtitle_y=y;
}

function qIsTalking() {
  if (squeue.ol!=null) return squeue.ol.Valid;
  else return 0;
}

function GetSoundNumber(String text) { //return 0 if unsuccessful
   String txt=text;

   int pos = txt.Contains("@");
   if (pos<0) return 0;
   int i = pos + 1;
   String str_rez="";
   while (i<txt.Length && txt.Chars[i]>='0' && txt.Chars[i]<='9') {
			str_rez=str_rez.AppendChar(txt.Chars[i]);
      i++;
   }

   while (i<=txt.Length) {
     String new_Str = "@";
      new_Str = new_Str.ReplaceCharAt(pos, i);
      i++;
      pos++;
   }

   return str_rez.AsInt;
}

function GetFreeChannel() { // returns a channel number
   if      (IsChannelPlaying(5)==0) return 5;
   else if (IsChannelPlaying(4)==0) return 4;
   else return 3;
}

function qStopSpeechChannel() {
   if (squeue.channel>2)
      if (IsChannelPlaying(squeue.channel)) {
         StopChannel(squeue.channel);
         squeue.channel = -1;
      }
}

function qStopSpeech() {
   if (qIsTalking()) {
      qStopSpeechChannel();
			if ((squeue.ol!=null) && squeue.ol.Valid) squeue.ol.Remove();
			if ((squeue.stol!=null) && squeue.stol.Valid) squeue.stol.Remove();
      int i = squeue.say % SPEECH_QUEUE_SIZE;
      if (squeue.c[i]!=null) squeue.c[i].UnlockView();
      if (squeue.prev_char != null) { squeue.prev_char.UnlockView(); squeue.prev_char = null; }
      squeue.stop_talk = 0;
      squeue.say = squeue.insert;
   }
}

function isnumchar (char c) {
  if (c=='-') return 1;
  else return (c>='0' && c<='9');
}

function SpecialHandler(String s) {
  int i=s.Contains("set-globalint ");
	if (i>=0) {
		i+=14;
    String str_rez="";
    while (i<s.Length && isnumchar(s.Chars[i])) {
			str_rez=str_rez.AppendChar(s.Chars[i]);
      i++;
    }
		int gi=str_rez.AsInt;
		i++;
		str_rez="";
    while (i<s.Length && isnumchar(s.Chars[i])) {
			str_rez=str_rez.AppendChar(s.Chars[i]);
      i++;
    }
		SetGlobalInt(gi, str_rez.AsInt);
		return 1;
	} else {
		i=s.Contains("add-score ");
		if (i>=0) {
			i+=10;	
			String str_rez="";
			while (i<s.Length && isnumchar(s.Chars[i])) {
				str_rez=str_rez.AppendChar(s.Chars[i]);
				i++;
			}
	    GiveScore(str_rez.AsInt);
	    return 1;
	  } else return 0;
	}
}	
 
function DisplaySpeechQ_RE() {

   if (qIsTalking()==0) { // wait for character to finish talking
      if (squeue.say < squeue.insert) { // if something left to be said

        int i = squeue.say % SPEECH_QUEUE_SIZE;

				if (!SpecialHandler(squeue.s[i])) {
					String buf;
					String new_Copy = buf;

					qStopSpeechChannel();
					int cur_sound = GetSoundNumber(buf);
					squeue.channel   = GetFreeChannel();
					if (cur_sound>0) PlaySoundEx(cur_sound, squeue.channel);

					squeue.ol = squeue.c[i].SayBackground(buf);
					if ((squeue.stol!=null) && squeue.stol.Valid) squeue.stol.Remove();
					if (squeue.st[i]!=null && squeue.st[i]!="") {
							squeue.stol = Overlay.CreateTextual((system.viewport_width-GetTextWidth(squeue.st[i], squeue.subtitle_font))/2, squeue.subtitle_y, 320, squeue.subtitle_font, squeue.subtitle_col, squeue.st[i]);
					}
				
					squeue.stop_talk = 1;

					if (squeue.prev_char != null) squeue.prev_char.UnlockView();
					squeue.prev_char = squeue.c[i];

					if (squeue.c[i].Animating==0 && squeue.noanim[i]==0) {
            int view = squeue.c[i].SpeechView;
            if (view < 1) { Display("error: Talk view isn't assigned!"); QuitGame(0); }
            int loop =squeue.c[i].Loop;
            int delay=squeue.c[i].AnimationSpeed;
            squeue.c[i].LockView(view);
            squeue.c[i].Animate(loop, delay, eRepeat, eNoBlock, eForwards);
					}

				}
        squeue.noanim[i] = 0;
        squeue.say++;
      } else if (squeue.stop_talk) { //finish talk animation
				 if ((squeue.stol!=null) && squeue.stol.Valid) squeue.stol.Remove();
         if (squeue.prev_char != null) { squeue.prev_char.UnlockView(); squeue.prev_char = null; }
         qStopSpeechChannel();
         squeue.stop_talk = 0;
      }
   } // end of if (qIsTalking()==0)
}

String str_delay;
String qDelay(int time){

   int n=time;
   if (n<1) n=1; else if (n>=AGS_STRING_LENGTH) n=AGS_STRING_LENGTH-1;

   String format;
   String.Format(format, "%%%dc", n);
   String.Format(str_delay, format, ' ');
   squeue.noanim[squeue.insert % SPEECH_QUEUE_SIZE] = 1;
   return str_delay;
}

String   qSetGlobalInt(int globalint, int value) {
  String.Format(str_delay, "set-globalint %d %d", globalint, value);
  squeue.noanim[squeue.insert % SPEECH_QUEUE_SIZE] = 1;
  return str_delay;
}
  
String   qAddScore(int points) {
  String.Format(str_delay, "add-score %d", points);
  squeue.noanim[squeue.insert % SPEECH_QUEUE_SIZE] = 1;
  return str_delay;
}

function qSkipCurrentMessage() {
   if (qIsTalking()) {
			squeue.ol.Remove(); // IsTalking already checks if null/valid
			if ((squeue.stol!=null) && squeue.stol.Valid) squeue.stol.Remove();
	 }
}



//Main global script file (Repeatedly execute):

function repeatedly_execute() {
  // put anything you want to happen every game cycle here
  
   DisplaySpeechQ_RE(); // place it before any other script code in rep. exec.
  
}



//Main global script file (on_event function):
function on_event(int event, int data) {

   if (event==eEventLeaveRoom) qStopSpeech();

}


function qSetSkippable(int skippable) {
  squeue.skippable=skippable;
}

// optional
// on_key_press:
function on_key_press (int keycode) {
  if (squeue.skippable && (game.skip_speech_specific_key>0) && (keycode==game.skip_speech_specific_key)) qSkipCurrentMessage();
}


I had to update all the String code, but it crashes on a RepExec function error on line 40 under the GetSoundNumber function on SSH's code. The problem is due to a null pointer referenced.

EDIT: I fixed the null errors by changing repeatedly_execute to RepExec but now background dialog never happens.

Khris

If you change "repeatedly_execute" to "RepExec" in a module script, the function will simply not be called anymore.
AGS is specifically looking for "repeatedly_execute", how would it know that now some other function is supposed to be called every loop?

The error is in line 132, where String buf isn't initialized to the next line of text in queue but null (which produces the null pointer error).
If should probably be
Code: ags
  String buf = squeue.s[i];

Secret Fawful

It works now. I had a couple other errors, but I managed to fix them. I should have asked SSH directly about these, but I'm tired and impatient. Anyway, thanks for the help. I'm doing things that I'm out of my league on here, but I don't know any other way to learn.

Snarky

No shame in being in over your head, it's the best way to learn. I'm surprised there'd be bugs in SSH's module, though, since it's been used in many games; I'm using it myself and don't remember running into this issue. Sorry about that.

SMF spam blocked by CleanTalk