Show Posts

You can view here all posts made by this member. Note that you can only see posts made in areas to which you currently have access.

Messages - Snarky

Pages: [1] 2 3 ... 287
I've tried to replicate this problem, but it works fine for me.

Is your game 32-bit? If not, that would explain all sorts of weirdness. The SpeechBubble module does not support 16-bit color, and I'm not sure whether this method for drawing strings does either. I strongly recommend that you don't use 16-bit.

If that's not the problem, try sending me your project (download link in a PM), and I'll take a look at it.

Try a different speech color.

Thanks! Could you also post your speech font and speech color settings, and SpeechBubble configuration?

Also, that white wedge that covers up some of the text in the second image, is there a reason for that or another bug?

Weird. Can you post a screenshot and your code that produces it?

As for just using the outline code without the module, as I said it's a little tricky, and it depends on exactly what you want it to do. For speech, I'd definitely recommend the module. For e.g. button text you'd need some code to take the button.Text property, create a dynamic sprite, draw the outline text to its drawing surface, and set the button graphic to the dynamic sprite. It gets complicated.

Edit: And if you're trying to put it on a label, I don't think you can.

The lack of good support for this in AGS is the reason for this code.

If you haven't used DrawingSurfaces it's probably a little tricky to make use of, but you can try the SpeechBubble module to see it in action. Set SpeechBubble.TextOutlineWidth to some value >1 to get a thicker outline.

Modules & Plugins / Re: MODULE: SpeechBubble v0.8.0
« on: Yesterday at 05:40 »
Hey! Finally playing around with this. I'm really digging it so far, but is there way to tell the module to NOT use a talking view for background speech? I use portrait view for all my characters and the module keeps changing the character sprite to the portrait. Thanks in advance! :)

edit: Aha! Nevermind. Figured it out.

Presumably you passed false for the animate parameter? I think that should do the trick.

I do have another question. Is there a way to set the position of the background bubble? There is an option to set the position of the standard bubble, but not the background one.

No, not at the moment. I'm not happy with the bubble positioning logic overall (I particularly want to ensure that the tail is always positioned to point to the character, even when the bubble butts up against the side of the screen), and it's one part I really want to redo.

However, unless this is urgent I'll put it on pause for a bit to focus on the Awards Ceremony.

OK, everyone who went straight to look up Danvzare's age and then smiled a little raise your hand. :-*

Le Woltaire! Good to see you around!

This feels like one of those cases where you've jumped ahead to what you assume is the solution, and you're asking us how to do that rather than how to solve your actual problem.

What is it you're trying to do? What behavior/experience are you trying to create?

Is it a plain Character.Say() call, or are you using any kind of custom function?

Snarky, hotspots are still limited to 50. You are probably referring to the old experimental version that allowed 256 of them, but that was never actually released.

Yeah, I did a forum search for 'hotspot limit' and trusted the first result I found. Should have looked more closely...

Also, the peculiarity of AGS script is that you cannot declare variable in "for", you need to do:
Code: Adventure Game Studio
  1. int i; // first declare it
  2. for (i = 0; ... etc

That can't be true. I use it all the time.

The basic idea of that second approach is good, it's just the syntax that's a little different:

Code: Adventure Game Studio
  1. // The max number of hotspots per room is 50 before AGS 3.4, 256 afterwards
  2. #ifver 3.4
  3.   #define MAX_HOTSPOTS 256
  4. #endif
  5. #ifnver 3.4
  6.   #define MAX_HOTSPOTS 50
  7. #endif
  9. function someFunction()
  10. {
  11.   // hotspot[0] is the "no hotspot", so skip that
  12.   for(int i=1; i < MAX_HOTSPOTS; i++)
  13.   {
  14.     hotspot[i].Enabled = false;
  15.   }
  16. }

I don't think AGS keeps track of how many of the available hotspots are actually used, but I think it's OK to access the properties of unused hotspots.

do you think I should re-post the question...

No. Always no.

Modules & Plugins / Re: MODULE: TotalLipSync v0.5
« on: 13 Jan 2018, 12:50 »
I wrote a little script to help people who use Rhubarb to do lip-syncing.

Rhubarb does the lip-sync tracking automatically by analyzing the audio, but you can also supply the actual text of the dialog to help guide it, improving the results. Using something like this batch file, you can then create the lip-sync tracking for the entire game automatically:

Code: Bash
  1. for %%F in (clips/*.wav) do (
  2.     rhubarb.exe clips/%%~nxF -d guide/%%~nF.txt > sync/%%~nF.tsv
  3. )

There hasn't been a convenient way to create these guide files from AGS, however. This script helps to automate the task.

It works with the voice acting HTML scripts generated by the Speech Center plugin. Once you've created the voice acting scripts, place them in a subfolder (e.g. /VoiceScripts) inside your compiled game folder. Place a call to this function in your game, and run it to extract the guide files, like so:

Code: Adventure Game Studio
  1.   ExtractVoiceScriptLines("$INSTALLDIR$/VoiceScripts", "$APPDATADIR$/guide");

(The output directory must be in $APPDATADIR$ or an existing subfolder of it. Where %APPDATADIR% is pointing can be set in winsetup.exe under Advanced.)

Here's the script (yeah, I know it's ugly, but it seems to work OK):
Code: Adventure Game Studio
  1. #define SCRIPT_TOKEN_LINE_NUMBER "<span class=\"lineNumber\">"
  2. #define SCRIPT_TOKEN_TEXT_START ":</b> "
  3. #define SCRIPT_TOKEN_TEXT_END "</span>"
  5. static String ExtractVoiceScriptLines(String sourceDirectory, String targetDirectory)
  6. {
  7.   int i=0;
  8.   String tokenLineNumber = String.Format("%s", SCRIPT_TOKEN_LINE_NUMBER);
  9.   String tokenTextStart = SCRIPT_TOKEN_TEXT_START;
  10.   String tokenTextEnd = SCRIPT_TOKEN_TEXT_END;
  11.   while(i < Game.CharacterCount)
  12.   {
  13.     String prefix = character[i].GetSpeechPrefix();
  14.     String scriptPath = String.Format("%s/char%s.html", sourceDirectory, prefix);
  15.     if(File.Exists(scriptPath))
  16.     {
  17.       File* scriptFile = File.Open(scriptPath, eFileRead);
  18.       String lineNumberPrefix = prefix;
  19.       while(!scriptFile.EOF)
  20.       {
  21.         String scriptLine = scriptFile.ReadRawLineBack();
  22.         int startLineNumberTag = scriptLine.IndexOf(tokenLineNumber);
  23.         if(startLineNumberTag != -1)
  24.         {
  25.           int startLineNumber = scriptLine.IndexOf(lineNumberPrefix);
  26.           int endLineNumber = scriptLine.IndexOf("]");
  27.           if(startLineNumber > 0 && endLineNumber > 0 && endLineNumber > startLineNumber + lineNumberPrefix.Length)
  28.           {
  29.             String strLineNumber = scriptLine.Substring(startLineNumber+lineNumberPrefix.Length, endLineNumber - startLineNumber - lineNumberPrefix.Length);
  30.             int lineNumber = strLineNumber.AsInt;
  31.             //Display("Writing %s%d", prefix, lineNumber);
  32.             if(lineNumber>0)
  33.             {
  34.               String message = "";
  35.               String dialogLine = scriptFile.ReadRawLineBack();
  36.               int startTextTag = dialogLine.IndexOf(tokenTextStart);
  37.               int endTextTag = dialogLine.IndexOf(tokenTextEnd);
  38.               if(startTextTag > 0)
  39.               {
  40.                 while(endTextTag == -1 && !scriptFile.EOF)
  41.                 {
  42.                   dialogLine = dialogLine.AppendChar(' ');
  43.                  dialogLine = dialogLine.Append(scriptFile.ReadRawLineBack());
  44.                   endTextTag = dialogLine.IndexOf(tokenTextEnd);
  45.                 }
  46.                 int textLength = endTextTag - startTextTag - tokenTextStart.Length;
  47.                 if(startTextTag > 0 && endTextTag > 0 && textLength >= 0)
  48.                   message = dialogLine.Substring(startTextTag+tokenTextStart.Length, textLength);
  50.                 String linePath = String.Format("%s/%s%d.txt", targetDirectory, prefix, lineNumber);
  51.                 //Display("Writing line \"%s\" to file %s", message, linePath);
  52.                 File* lineFile = File.Open(linePath, eFileWrite);
  53.                 if(lineFile != null)
  54.                 {
  55.                   //Display("Writing line \"%s\" to file %s", message, linePath);
  56.                   lineFile.WriteRawLine(message);
  57.                   lineFile.Close();
  58.                 }
  59.                 else
  60.                   Display("Couldn't write line \"%s\" to file %s", message, linePath);
  61.               }
  62.             }
  63.           }
  64.         }
  65.       } // while(!scriptFile.EOF)
  66.       scriptFile.Close();
  67.     }
  68.     i++;
  69.   }
  70. }

No, the mistake was mine. (I was a little drunk when I wrote it.) Try this for the two functions:

Add spoiler tag for Hidden:
Code: Adventure Game Studio
  1. // Round off the corners of the bubble by erasing to transparent
  2. void drawRoundedCorners32(DrawingSurface* background, int left, int top, int right, int bottom)
  3. {
  4.   // Uses Bresenham's circle formula, found online
  5.   int r = _cornerRoundingRadius - 1;
  7.   int x = 0;
  8.   int y = r;
  9.   int p = 3 - 2 * r;
  10.   int dc = background.DrawingColor;
  11.   background.DrawingColor = COLOR_TRANSPARENT;
  12.   while (y >= x) // only formulate 1/8 of circle
  13.   {
  14.     // Erase background corners
  15.     // Top Left
  16.     background.DrawLine(left + r - x, top+r - y, left + r - x, top);
  17.     background.DrawLine(left + r - y, top+r - x, left + r - y, top);
  19.     // Top Right
  20.     background.DrawLine(right - r + y, top+r - x,  right - r + y, top);
  21.     background.DrawLine(right - r + x, top+r - y,  right - r + x, top);
  23.     // Bottom Left
  24.     background.DrawLine(left + r - x, bottom-r + y, left + r - x,  bottom);
  25.     background.DrawLine(left + r - y, bottom-r + x, left + r - y,  bottom);
  27.     // Bottom Right
  28.     background.DrawLine(right - r + y, bottom-r + x, right - r + y, bottom);
  29.     background.DrawLine(right - r + x, bottom-r + y, right - r + x, bottom);
  31.     if (p < 0)
  32.     {
  33.       p += 4*x + 6;
  34.       x++;
  35.     }
  36.     else
  37.     {
  38.       p += 4*(x - y) + 10;
  39.       x++;
  40.       y--;
  41.     }
  42.    }
  43.    background.DrawingColor = dc;
  44. }

Code: Adventure Game Studio
  1. // Draw a speech bubble in 32-bit (using transparency)
  2. DynamicSprite* renderBubble32(this Character*, String message, bool talkTail)
  3. {
  4.   // Calculate text dimensions
  5.   int textWidth = _maxTextWidth;
  6.   if(textWidth <= 0)
  7.     textWidth = calculateDefaultTextWidth(this);
  8.   textWidth = _minInt(textWidth, System.ViewportWidth - _paddingLeft - _paddingRight);
  9.   int textHeight = GetTextHeight(message, Game.SpeechFont, textWidth);
  10.   textWidth = calculateExactTextWidth(message, Game.SpeechFont, textWidth, textHeight);
  12.   // Calculate bubble dimensions
  13.   int totalWidth = textWidth + _paddingLeft + _paddingRight;
  14.   int bubbleHeight = textHeight + _paddingTop + _paddingBottom;
  15.   int totalHeight;
  16.   if(talkTail)
  17.     totalHeight = bubbleHeight + _talkTailHeight;
  18.   else
  19.     totalHeight = bubbleHeight + _thinkTailHeight;
  21.   // Set up the canvases
  22.   DynamicSprite* bubbleSprite = DynamicSprite.Create(totalWidth, totalHeight, true);
  23.   DrawingSurface* bubbleSurface = bubbleSprite.GetDrawingSurface();
  24.   //bubbleSurface.Clear();
  26.   DynamicSprite* bgSprite; DrawingSurface* bgSurface;
  27.   DynamicSprite* borderSprite; DrawingSurface* borderSurface;
  28.   bgSprite = DynamicSprite.Create(totalWidth, totalHeight, true);
  29.   bgSurface = bgSprite.GetDrawingSurface();
  30.   borderSprite = DynamicSprite.Create(totalWidth, totalHeight, true);
  31.   borderSurface = borderSprite.GetDrawingSurface();
  33.   int bgColor = mixColors(this.SpeechColor, _backgroundColor, _backgroundSpeechTint);
  34.   int borderColor = mixColors(this.SpeechColor, _borderColor, _borderSpeechTint);
  36.   // Draw!
  37.   bgSurface.DrawingColor = bgColor;
  38.   borderSurface.DrawingColor = borderColor;
  39.   bgSurface.DrawRectangle(0, 0, totalWidth-2, bubbleHeight-2);
  40.   borderSurface.DrawRectangle(1,  1, totalWidth-1, bubbleHeight-1);
  41.   if(_cornerRoundingRadius > 0)
  42.   {
  43.     drawRoundedCorners32(bgSurface, 0, 0, totalWidth-2, bubbleHeight-2);
  44.     drawRoundedCorners32(borderSurface, 1, 1, totalWidth-1, bubbleHeight-1);
  45.   }
  46.   String tail[]; int tailWidth; int tailHeight;
  47.   if(talkTail)
  48.   {
  49.     tail = _talkTail; tailWidth = _talkTailWidth; tailHeight = _talkTailHeight;
  50.   }
  51.   else
  52.   {
  53.     tail = _thinkTail; tailWidth = _thinkTailWidth; tailHeight = _thinkTailHeight;
  54.   }
  55.   bgSurface.drawPixelArray(tail, totalWidth/2-tailWidth, bubbleHeight-1, tailWidth, tailHeight, 'O', false, false);
  56.  borderSurface.drawPixelArray(tail, totalWidth/2-tailWidth+1, bubbleHeight, tailWidth, tailHeight, 'O', false, false);
  58.   borderSurface.Release();
  59.   bubbleSurface.DrawImage(0, 0, borderSprite.Graphic, _borderTransparency);
  60.   borderSprite.Delete();
  62.   bgSurface.Release();
  63.   bubbleSurface.DrawImage(0, 0, bgSprite.Graphic, _backgroundTransparency);
  64.   bgSprite.Delete();
  66.   bubbleSurface.DrawingColor = this.SpeechColor;
  67.   int outlineColor = mixColors(this.SpeechColor, _textOutlineColor, _textOutlineSpeechTint);
  68.   if(_textOutlineWidth > 0)
  69.     bubbleSurface.drawStringWrappedOutline(_paddingLeft, _paddingTop, textWidth, _textOutlineStyle, Game.SpeechFont, _textAlign, message, _textTransparency, outlineColor, _textOutlineWidth);
  70.   else
  71.     bubbleSurface.drawStringWrappedAA(_paddingLeft, _paddingTop, textWidth, Game.SpeechFont, _textAlign, message, _textTransparency);
  73.   bubbleSurface.Release();
  74.   return bubbleSprite;
  75. }
Note that I've also adjusted how the corner rounding parameter is used: you might want to increase it by 1 to get the same results as with the original version.

One thing: it looks like you're editing the initSpeechBubble() function in order to configure the module. This is not how it's meant to be used: You're not supposed to edit the module code at all (except as otherwise instructed). Rather, as the header documentation explains, you're supposed to configure it from outside, e.g. in your game's GlobalScript. For your settings, that would be something like:

Add spoiler tag for Hidden:
Code: Adventure Game Studio
  1. // in GlobalScript.asc
  3. function game_start()
  4. {
  5.   // Setup SpeechBubble module
  6.   SpeechBubble.CornerRoundingRadius = 3;
  7.   SpeechBubble.PaddingTop = 5;
  8.   SpeechBubble.PaddingBottom = 4;
  9.   SpeechBubble.PaddingLeft = 9;
  10.   SpeechBubble.PaddingRight =9;
  12.   // (You don't need the shadow any more, it's now drawn automatically)
  13.   String tail[] = new String[5];
  14.   tail[0] = " OOOO";
  15.   tail[1] = "  OOO";
  16.   tail[2] = "   OO";
  17.   tail[3] = "    O";
  18.   tail[4] = null;
  20.   SpeechBubble.TalkTail = tail;
  21. }
However, when I test, I see that that last line doesn't work – an AGS limitation I wasn't aware of. I will fix it so you can write:

Code: Adventure Game Studio
  1.   SpeechBubble.SetTalkTail(tail);

In the mean time you can leave the setup as you have it.

1) What do you like about AGS, and would like to keep if any new creative tool arrives?
2) What do you think should be changed (added, removed, altered)?

Overall I like the AGS way of doing things. It strikes a nice balance between being pretty easy to just pick up and use and being quite powerful. But there are many points that could be improved or streamlined, and many tasks that are way more tedious than they ought to be.

One of the best things is the "make my game" button: By which I mean, there's a very simple and easy-to-find option that will build a ready-to-distribute version of your game, complete with config program and everything. With the Awards Ceremony, I have on several occasions had to patch some bug and distribute a new version of the client in a matter of minutes, and AGS makes that a pretty painless process.

It could be improved further, though: first of all, I never understood why after running the game in debug mode, the exe file disappears from the compiled folder. Really annoying. Secondly, maybe some way to package it as an installer would make life even easier for newbies.

Second, I think the unified IDE that covers both coding and asset management is key. Convenience and "works right out of the box"-ness is what makes AGS such an appealing choice for new users.

On the improvement side, I agree that the way assets are "trapped" in the editor rather than existing on the file system, and the way tools like the compiler can only be called from the editor (so that you can't script automated builds, for example) are major, needless limitations. I also agree with Radiant that that the UI could be improved in many places, and with CrashPL about the graphics UIs specifically (e.g. zooming, which is implemented inconsistently throughout, between sprites, views, characters, rooms...).

I also always found the View system really unintuitive and tedious for working with animations. The way it mixes together different angles of the same animation and different animations is weird, and having the angles hardcoded makes it difficult whenever you want less than 4 different angles (e.g. only left and right animations, or only up and down animations). I think it would be better if a view were only different angles on "the same" animation, and to group related animations together you'd simply place them in a folder. (The main change needed would be the ability to view all the animation loops in a folder in the same animation editor tab.)

The AGS documentation is overall very good: I use the manual all the time from within the editor. Having that and not having to open a browser to look stuff up is really important. The AGS community and all the technical knowledge available on the forums (old threads as well as live advice) is irreplaceable.

There's a lot of room for improvement there as well, particularly in documenting the editor and making a reference section for things that are currently only described in the tutorial/introduction, but the most important thing would be to have an up-to-date version of the manual online; among other things, it would make it easier to help others because you could just refer them to the right place in the manual.

Also having the "IntelliSense" capabilities (tooltip hints for functions, autocomplete) in the code editor is of course really important, though that's probably a baseline expectation these days. I love that you can add tooltip help for new functions etc. using the triple slash comments. (It just occurred to me that it might be cool to extend these contextual hints further to e.g. preview a sprite or an animation just by hovering over the code, but it's not really something I've been missing.)

I actually think the biggest code editor annoyance is that it feels slightly buggy: not very good at picking up updates to your code, search not working reliably, etc. Also on the coding side I think debugging could be improved, particularly to make it easier to inspect the value of variables at different points in the code. And I seem to recall that one of step-over/into is missing, making it more tedious that it ought to be to reach the point in your code you want to check.

More ambitiously, I really like tzachs' idea of being able to edit script from within the game, by e.g. writing dialog as you're playing. (I'm not exactly how his version works, but I was imagining that when you reach some undefined interaction, it'd pop up a little code editing window where you could just type in what would happen.) Live reloading of scripts would probably mean working in an interpreted language, as I understand it.

Staying on the topic of the code editor: having to put all the character/GUI/I-forget-what-else interaction handlers in GlobalScript is fucking idiotic, and I hate it.

With the recent additions of standard constructs like for loops and case statements, AGS Script is a pretty decent scripting language, and well suited for the game logic of a typical adventure game. Maybe a language like Lua or JavaScript (or TypeScript) would be better, but it seems like there are a bunch of drawbacks to any alternative as well.

The two things that would need improvement in my book is first, some easier way to script a non-blocking wait (it's a very common use-case, and one of the most frequent things newbies struggle with), just the way Game.DoOnceOnly() makes it really easy to script something to happen only once. I know it's hard to fit into the way the engine threads work, but maybe a new keyword that would introduce some very limited function pointer capability?

The other things is of course fixing the pointer/struct limitations, presumably by implementing a garbage collector. I've written probably thousands of lines of code that would be instantly redundant with that capability.

Obviously you replace "lblHotspotName" with the name of the label that you use to display the hotspot name.

Also, your assignment should be the other way around, the way CW did it.

Try posting the sprite here.

That's good, but 'closer'? Doesn't it give exactly the result in your example?

The Rumpus Room / Re: What's on TV?
« on: 11 Jan 2018, 06:57 »
One of the two Anne of Green Gables series that have recently come out? (One of them was called 'Anne with an E'.)

Pages: [1] 2 3 ... 287