[SOLVED! AGAIN!] Hidden Characters Contributing to String Length

Started by Baron, Thu 03/07/2014 15:51:07

Previous topic - Next topic

Baron

So I just rewrote my speech bubble code so that the speech bubbles conform more closely in size to the length of text presented therein.  Usually this wasn't an issue with the old code, but for very short strings (e.g. "No.") it looked a little funny with a bubble that was way too long.  So now I'm calculating the bubble width dynamically using an algorithm based on the string length, and it works perfectly now even with strings as short as "!".  But then I was testing with some voice files for voice speech and discovered, to my horror, that the  invisible characters that denote which speech file to play (e.g. "&1") contribute to the string length!  So now I'm back to having a large gap of white space around my very short strings, thereby negating all my efforts. >:(
    So my question is, is there a way to dynamically calculate the length of the "&xxx" substring, so that I can subtract it from the length of my total string?  The "&" character is easy (length =40 at the font I'm using), but the number could be anything from 1 to the hundreds....  If I was using ActionScript I'm pretty sure I could build a string out of two smaller strings and thus determine their length separately, but I haven't been able to figure out a way to do that in AGS.  Can anyone help a brother out?  Thanks!

geork

Hello Baron;

Two solutions came to my mind - one a bit of work, and the other one speculative:

For the speculative one - does AGS support "&001" as well as "&1"? Might be worth a try, because then you can always take the same amount of characters from your string.

The Other Method may be to create a custom function which accepts both the text and the invisible characters - maybe:
Code: ags
Character.Speak(String Text, String Speech)

So you would use it like:
Code: ags
cEgo.Speak("My, what a fine bottle of shampoo","&1");

You can then get the first String and use it's length for the bubble, then combine both strings. (Using String.Append()) It'll be a bit more hassle, since you'll have to go through all instances of when the character speaks and replace them, but this method should hopefully work :)

Hope that helps!

monkey0506

If you're already calculating the width based on the string's length, then all that's left to do is snip that bit off before you check the length...

Code: ags
String text = "&1Hello World!"; // presumably this would actually be a function parameter (static text is for example purposes only, and otherwise doesn't make sense :P)
String buffer = text;
if (text.StartsWith("&"))
{
  int i = 1;
  bool break = false;
  while ((i < text.Length) && (!break)) // find the first character that is not a number
  {
    break = ((text.Chars[i] < '0') || (text.Chars[i] > '9')); // break out of the loop if character i is not a number
    i++;
  }
  if (i < text.Length) buffer = text.Substring(i, text.Length - i);
  else buffer = "";
}
// now do the algorithm against buffer.Length instead of text.Length

Baron

Snipping!  I love snipping!  Talkstring.Snip (extras)!  Your code works like charm, Mr. Monkey_05_06.  A thousand thank yous. (nod) ;-D

monkey0506

I'm glad you got it working the way you needed. :) Cheers!

Spoiler
Code: ags
// WARNING: THE FOLLOWING CODE IS FOR DEMONSTRATIVE PURPOSES ONLY AND IS NOT FIT FOR ACTUAL USE
int GetAdjustedLength(String text)
{
  if (text == null) text = "";
  String buffer = text;
  if (buffer.StartsWith("&"))
  {
    // instead of looping through the whole string, you could...
    buffer = buffer.Substring(1, buffer.Length - 1); // snip the ampersand off
    int i = buffer.AsInt; // snag the integer value (assuming it starts with a value less than 2.14 billion)
    String buffer2 = String.Format("%d", i); // format the integer back as a string
    if (!String.IsNullOrEmpty(buffer2)) // (optional) safety check
    {
      if (!buffer.StartsWith(buffer2)) AbortGame("Blast, this convoluted mess didn't work for \"%s\"", text); // (optional) safety check
      buffer = buffer.Substring(buffer2.Length, buffer.Length - buffer2.Length); // truncate the integer length from the buffer
      // the additional safety checks, allocations, and copying this requires will most likely result in less efficient code
      // than just iterating the string yourself (even though the C++ code the engine invokes is faster than the raw AGScript)
      // also, don't ask my why I posted this. I just thought it was an interesting approach, though I'd stick to the first code.
    }
  }
  int length = buffer.Length;
  // do algorithm and stuff
  return length;
}
[close]

Baron

Gah!  Memory problems.  I had them before, once, and was convinced that it was a corrupt room file.  However, deleting the room didn't solve the problem so I had to go back to a previous build of my game and rebuild.  Which implies that it wasn't a corrupt room file at all, but a broader mysterious problem that was never solved.

Anyway, now I'm getting this:


Apparently this has been a problem for other developers recently, and it happens for me now when speech starts, which can not be a coincidence.  But I haven't altered any of the speech code since I established that it worked a couple weeks back, and I have tested the width of my speech bubble by displaying it before the bubble is called, and it is always positive (I commented out a bunch of speech to try out random lines, but they all crash the game now).  It seems like it must be a corrupt room file again -or at least the mysterious corruption again- but why does it always crash on speech....?  My speech bubble function uses Sierra with Background speech with SayAt commands: it's too much of a coincidence.

What have I changed since getting the speech bubble function to work a few weeks back?  Just added another background to the same room, some objects, and a couple of new speech views.  I cannot even remember opening the global script since the speech bubble function worked....

So, since I haven't changed anything with the working code, this seems to be a recurrence of the random room file mystery corruption that I suffered from last summer.  But... why does the game always crash now during speech?  Why am I getting virtually the same error Dave was getting when his SayAt width was negative?  Why was he able to fix his game so easily?!? :P  Does anyone have any ideas, or is it back to square one for me (again....)?

Crimson Wizard

Although Dave Gilbert explained how he got this, back then I could not reproduce it.
Is there a chance you may PM me your game? I just want to run it under debugger and see what happens in the engine.

Baron

Upon reflection, I see another common thread to this error.  Both times it occurred after I changed the character view while both the character tab was open and the same character was the focus in the room I was working on.  Can it be that the editor can't handle updating the properties of one while the other is open at the same time?

@Crimson Wizard: PMed!

Crimson Wizard

So far I found that when you call SayAt the "width" parameter must be >= width of speech frame, because it actually limits both text AND portrait size.

If it's less, it causes all kinds of weird results, eventually trying to create an overlay bitmap of many-GB in size.

Baron

Could you post the code or a line number that you think is causing the weird results?  I'm not saying that leaky code might not be a possibility here (and that's why I posted in this same thread), but it is definitely suspicious that I had the same crash last summer with different code, and that the speech bubbles were all working fine last week. :-\

Crimson Wizard

#10
SayAt causes this when width parameter is less than size of portrait. For example, the one in custom Character.TalkAt function.

Baron

Quote from: Crimson Wizard on Sun 27/07/2014 22:43:55
So far I found that when you call SayAt the "width" parameter must be >= width of speech frame, because it actually limits both text AND portrait size.

If it's less, it causes all kinds of weird results, eventually trying to create an overlay bitmap of many-GB in size.

Alright, I got it.  Good call on the speech frame portrait size.  What I had done was swapped the blank frame from loop 0 of View 1 to a character sprite in order to place it precisely in the room (thus playing with the character attributes, making me suspect that that was the cause).  However, I forgot that the reason View 1 has empty sprites in all 4 views is not an oversight but was actually my invisible portrait frames for my custom speech bubble TalkAt function.  As soon as I swapped the blank sprite back into View 1 the game ran normally -1000 thank yous! ;-D ;-D ;-D 

I wonder if this is what I inadvertently did last time....  I'm pretty sure I have a back up of the "corrupted" file: I should go check.

SMF spam blocked by CleanTalk