Jibble

Author Topic: MODULE: SpeechBubble v0.8.0  (Read 10713 times)

bx83

  • Get 'Er Doooooone
Re: MODULE: SpeechBubble v0.8.0
« Reply #60 on: 28 Jul 2019, 09:33 »
Will this slow it down, have the old compiler etc. and basically be like using 3.4.1?

Re: MODULE: SpeechBubble v0.8.0
« Reply #61 on: 28 Jul 2019, 10:04 »
Will this slow it down, have the old compiler etc. and basically be like using 3.4.1?

It simply enables old script commands. They are hidden but still there.

bx83

  • Get 'Er Doooooone
Re: MODULE: SpeechBubble v0.8.0
« Reply #62 on: 18 Aug 2019, 11:31 »
Cool, got it, changed and works.

I have a question for Snarky (or anyone if they know the answer).
SpeechBubble has a border of custom thickness and colour to text in the speech bubble. How do I do this elsewhere in the game?
I have an item description as a GUI with a label containig '@OVERHOTSPOT@', positioned at the top-centre of screen. How can I make this text with a 2px thickness black border, just as text in SpeechBubble?

Snarky

  • Global Moderator
  • Private Insultant
    • Best Innovation Award Winner 2018, for his numerous additions to the AGS open source ecosystem including the new Awards Ceremony client and modules
    • Snarky worked on one or more games that won an AGS Award!
    •  
    • Snarky worked on one or more games that was nominated for an AGS Award!
Re: MODULE: SpeechBubble v0.8.0
« Reply #63 on: 18 Aug 2019, 11:42 »
SpeechBubble uses custom code to draw the outline (the function drawStringWrappedOutline()). To get this effect elsewhere in the game you would have to copy that code and draw the text yourself onto a dynamic sprite (shown as an overlay, GUI, etc.).

The AGS devs are currently working on incorporating something similar into the engine, but I'm not sure whether that covers all text or only speech.

Re: MODULE: SpeechBubble v0.8.0
« Reply #64 on: 18 Aug 2019, 19:54 »
… colour to text in the speech bubble. How do I do this elsewhere in the game?

As concerns the colour of the outline in standard AGS without modules, see game.text_shadow_color (look for "game. variables" in the index of the online doc). You'll need to set the variable immediately before the  Say() or  Display() or whatever command and reset it immediately afterwards because this variable pertains to all outlines -- keep it at a certain value and the outlines will be coloured that way everywhere.

For my recent game Mamma mia Winter Ice Cream Mayhem, I've patched the Engine at the same place that the new code for variable outline thickness is going to go. I got thick outlines in the status line, too. So I think that the thick outlines will come everywhere, not only in Say().
« Last Edit: 18 Aug 2019, 20:26 by fernewelten »

bx83

  • Get 'Er Doooooone
Re: MODULE: SpeechBubble v0.8.0
« Reply #65 on: 20 Aug 2019, 02:28 »
To be clear, I mean the black colour around the font (the Stroke, for any photoshop aficionados), that fits the front perfectly like tight fitting clothing, not the rounded square frame around the speech bubble. Does anyone know which functions constitute this in speechbubble?

Snarky

  • Global Moderator
  • Private Insultant
    • Best Innovation Award Winner 2018, for his numerous additions to the AGS open source ecosystem including the new Awards Ceremony client and modules
    • Snarky worked on one or more games that won an AGS Award!
    •  
    • Snarky worked on one or more games that was nominated for an AGS Award!
Re: MODULE: SpeechBubble v0.8.0
« Reply #66 on: 20 Aug 2019, 07:00 »
Like I said, drawStringWrappedOutline().

bx83

  • Get 'Er Doooooone
Re: MODULE: SpeechBubble v0.8.0
« Reply #67 on: 21 Aug 2019, 03:34 »
Okay, I've attempted to copy this function (now called oulinedMessage) from speechbubble, and transplant my own outlineDrawStringWrappedAA into the function:

I've reduced the number of arguments, and supplanted default values hard-coded - these items will never change:

GlobalScript.asc
Code: Adventure Game Studio
  1. // Draw a string with outline (make sure the canvas has at least outlineWidth pixels on each side of the string)
  2. function outlinedMessage(this DrawingSurface*, int x, int y, int width, String message)
  3. {
  4.  
  5.   // This is what we draw on (because we might need to copy with transparency)
  6.   DynamicSprite* outlineSprite = DynamicSprite.Create(this.Width, this.Height, true);
  7.   DrawingSurface* outlineSurface = outlineSprite.GetDrawingSurface();
  8.  
  9.   // This holds multiple horizontal copies of the text
  10.   // We copy it multiple times (shifted vertically) onto the outlineSprite to create the outline
  11.   DynamicSprite* outlineStripSprite = DynamicSprite.Create(this.Width, this.Height, true);
  12.   DrawingSurface* outlineStripSurface = outlineStripSprite.GetDrawingSurface();
  13.  
  14.   // This is our "text stamp" that we use to draw the outline, we copy it onto outlineStripSprite
  15.   DynamicSprite* textSprite = DynamicSprite.Create(this.Width, this.Height, true);
  16.   DrawingSurface* textSurface = textSprite.GetDrawingSurface();
  17.  
  18.   // Draw our text stamp
  19.   textSurface.DrawingColor = 682;
  20.   textSurface.DrawStringWrapped(x, y, width, 1, 2, message);
  21.   textSurface.Release();
  22.  
  23.   // Draw Circular outline
  24.   int maxSquare = 2*2+1; // Add 1 for rounding purposes, to avoid "pointy corners"
  25.   int maxWidth = 0;
  26.   outlineStripSurface.DrawImage(0, 0, textSprite.Graphic);
  27.  
  28.   // We loop from top and bottom to the middle, making the outline wider and wider, to form circular outline
  29.   for(int i = 2; i > 0; i--)
  30.   {
  31.     // Here's the circular calculation...
  32.     while(i*i + maxWidth*maxWidth <= maxSquare)
  33.     {
  34.       // Increase width of the outline if necessary
  35.       maxWidth++;
  36.       outlineStripSurface.DrawImage(-maxWidth, 0, textSprite.Graphic);
  37.       outlineStripSurface.DrawImage(maxWidth, 0, textSprite.Graphic);
  38.       outlineStripSurface.Release();
  39.       outlineStripSurface = outlineStripSprite.GetDrawingSurface();
  40.     }
  41.     // Draw outline strip above and below
  42.     outlineSurface.DrawImage(0, -i, outlineStripSprite.Graphic);
  43.     outlineSurface.DrawImage(0, i, outlineStripSprite.Graphic);
  44.   }
  45.   // Finally the middle strip
  46.   outlineSurface.DrawImage(0, 0, outlineStripSprite.Graphic);
  47.  
  48.   textSprite.Delete();
  49.   outlineStripSurface.Release();
  50.   outlineStripSprite.Delete();
  51.  
  52.   /// Now draw the text itself on top of the outline
  53.   outlineSurface.DrawingColor = this.DrawingColor;
  54.  
  55.   //BEGIN OUTLINE DRAW STRING WRAPPED AA
  56.  
  57.   DynamicSprite* atextSprite = DynamicSprite.Create(this.Width, this.Height, true);
  58.   DrawingSurface* atextSurface = atextSprite.GetDrawingSurface();
  59.   atextSurface.DrawingColor = this.DrawingColor;
  60.   atextSurface.DrawStringWrapped(x, y, width, 1, 2, message);
  61.   atextSurface.Release();
  62.   this.DrawImage(0, 0, atextSprite.Graphic, 0);
  63.   atextSprite.Delete();
  64.  
  65.   //END OUTLINE DRAW STRING WRAPPED AA
  66.  
  67.   outlineSurface.Release();
  68.   // ... And copy it onto our canvas
  69.   this.DrawImage(100, 100, outlineSprite.Graphic, 0);
  70.   outlineSprite.Delete();
  71. }

GlobalScript.ash:
Code: Adventure Game Studio
  1. import function outlinedMessage(this DrawingSurface*, int x, int y, int width, String message);

in room2.asc:
Code: Adventure Game Studio
  1. function room_AfterFadeIn()
  2. {
  3.   ...
  4.  
  5.   outlinedMessage(100, 100, 100, "checking this out");
  6. }

But I get the error:
Failed to save room room2.crm; details below
room2.asc(5): Error (line 5): Undefined token 'outlinedMessage'

oulinedMessage() is at the top of GlobalScript.asc
The definition is at the top of the function definitions in GlobalScript.ash (after some #define's and enums)

...wtf has happened? It must be something incredibly obvious, but I can't see how room2 can't see GlobalScript.

Snarky

  • Global Moderator
  • Private Insultant
    • Best Innovation Award Winner 2018, for his numerous additions to the AGS open source ecosystem including the new Awards Ceremony client and modules
    • Snarky worked on one or more games that won an AGS Award!
    •  
    • Snarky worked on one or more games that was nominated for an AGS Award!
Re: MODULE: SpeechBubble v0.8.0
« Reply #68 on: 21 Aug 2019, 06:37 »
Well, that's because it's a "this" extender function, which has to be called on a DrawingSurface.

I'll take a look at adapting it to your needs.

Snarky

  • Global Moderator
  • Private Insultant
    • Best Innovation Award Winner 2018, for his numerous additions to the AGS open source ecosystem including the new Awards Ceremony client and modules
    • Snarky worked on one or more games that won an AGS Award!
    •  
    • Snarky worked on one or more games that was nominated for an AGS Award!
Re: MODULE: SpeechBubble v0.8.0
« Reply #69 on: 24 Aug 2019, 16:33 »
OK, here you go:

Keep drawStringWrapped() as it is. Just add this line to SpeechBubble.ash so you can call it from outside the module:

Code: Adventure Game Studio
  1. import void drawStringWrappedOutline(this DrawingSurface*, int x, int y, int width, TextOutlineStyle outlineStyle, FontType font,  Alignment alignment, String message, int transparency, int outlineColor, int outlineWidth);

Create a GUI that will display the mouseover text. It should be empty, without anything on it. Set the size and position to fit any text it will display. Make the background and border transparent, and make sure it's not clickable. I've named mine gFloatingText, but you can use any name.

Add this code to the script of the module that handles your UI, or as its own module:

Code: Adventure Game Studio
  1. // Replace these values with whatever you want
  2. #define FLOATING_TEXT_GUI gFloatingText
  3. #define FLOATING_TEXT_FONT eFontfntSpeech
  4. #define FLOATING_TEXT_OUTLINE_WIDTH 3
  5. #define FLOATING_TEXT_COLOR 11
  6. #define FLOATING_TEXT_OUTLINE_COLOR 0
  7.  
  8. String textContent;
  9. DynamicSprite* sprtFloatingText;
  10.  
  11. void SetFloatingText(String floatingText)
  12. {
  13.   if(textContent == null)
  14.     textContent = "";
  15.   if(floatingText != textContent)
  16.   {
  17.     textContent = floatingText;
  18.     if(sprtFloatingText == null)
  19.       sprtFloatingText = DynamicSprite.Create(FLOATING_TEXT_GUI.Width, FLOATING_TEXT_GUI.Height, true);
  20.     DrawingSurface* dsFloatingText = sprtFloatingText.GetDrawingSurface();
  21.     dsFloatingText.Clear(COLOR_TRANSPARENT);
  22.     if(!String.IsNullOrEmpty(textContent))
  23.     {
  24.       dsFloatingText.DrawingColor = FLOATING_TEXT_COLOR;
  25.       dsFloatingText.drawStringWrappedOutline(FLOATING_TEXT_OUTLINE_WIDTH,
  26.                                               FLOATING_TEXT_OUTLINE_WIDTH,
  27.                                               FLOATING_TEXT_GUI.Width - 2*FLOATING_TEXT_OUTLINE_WIDTH,
  28.                                               eTextOutlineRounded,
  29.                                               FLOATING_TEXT_FONT,
  30.                                               eAlignCentre,
  31.                                               textContent,
  32.                                               0,
  33.                                               FLOATING_TEXT_OUTLINE_COLOR,
  34.                                               FLOATING_TEXT_OUTLINE_WIDTH);
  35.     }
  36.     dsFloatingText.Release();
  37.     FLOATING_TEXT_GUI.BackgroundGraphic = sprtFloatingText.Graphic;
  38.   }
  39. }

Now whenever you want to set the content of this "label" you just call SetFloatingText(). I'm not sure you can use the @OVERHOTSPOT@ symbol (actually, I'm pretty sure it won't work), but you can use Game.GetLocationName(mouse.x,mouse.y) in repeatedly_execute() – see the TwoClickHandler template for an example.

bx83

  • Get 'Er Doooooone
Re: MODULE: SpeechBubble v0.8.0
« Reply #70 on: 26 Aug 2019, 01:21 »
Imported it all into global script/header. Set defines in header, put first 2 variables (line 3 and 4 in GlobalScript.asc) in function.
Works, compiles.

Does the GUI have an actual label control in it, or you're just referring to the whole thing as a label?

Also changed #define FLOATING_TEXT_FONT eFontfntSpeech from line 5 to eFontSpeech - this way it compiles. Correct usage? Otherwise it won't compile.

GetLocationName(mouse.x, mouse.y) gets a location's (Hotspot, Object, etc.) 'Description' (in the editor, in Properties window, under Appearance)?


Here's what I have:

GlobalScript.ash
Code: Adventure Game Studio
  1. //for gFloatingText 'description of what mouse is over'
  2. ...
  3. //for gFloatingText 'description of what mouse is over'
  4. #define FLOATING_TEXT_GUI gFloatingText
  5. #define FLOATING_TEXT_FONT eFontSpeech
  6. #define FLOATING_TEXT_OUTLINE_WIDTH 2
  7. #define FLOATING_TEXT_COLOR 49664
  8. #define FLOATING_TEXT_OUTLINE_COLOR 0
  9. import function SetFloatingText(String floatingText);
  10. import void drawStringWrappedOutline(this DrawingSurface*, int x, int y, int width, TextOutlineStyle outlineStyle, FontType font,  Alignment alignment, String message, int transparency, int outlineColor, int outlineWidth);
  11. ...

GlobalScript.asc
Code: Adventure Game Studio
  1. function SetFloatingText(String floatingText)
  2. {
  3.   String textContent;
  4.   DynamicSprite* sprtFloatingText;
  5.  
  6.   if(textContent == null)
  7.     textContent = "";
  8.   if(floatingText != textContent)
  9.   {
  10.     textContent = floatingText;
  11.     if(sprtFloatingText == null)
  12.       sprtFloatingText = DynamicSprite.Create(FLOATING_TEXT_GUI.Width, FLOATING_TEXT_GUI.Height, true);
  13.     DrawingSurface* dsFloatingText = sprtFloatingText.GetDrawingSurface();
  14.     dsFloatingText.Clear(COLOR_TRANSPARENT);
  15.     if(!String.IsNullOrEmpty(textContent))
  16.     {
  17.       dsFloatingText.DrawingColor = FLOATING_TEXT_COLOR;
  18.       dsFloatingText.drawStringWrappedOutline(FLOATING_TEXT_OUTLINE_WIDTH,
  19.                                               FLOATING_TEXT_OUTLINE_WIDTH,
  20.                                               FLOATING_TEXT_GUI.Width - 2*FLOATING_TEXT_OUTLINE_WIDTH,
  21.                                               eTextOutlineRounded,
  22.                                               FLOATING_TEXT_FONT,
  23.                                               eAlignCentre,
  24.                                               textContent,
  25.                                               0,
  26.                                               FLOATING_TEXT_OUTLINE_COLOR,
  27.                                               FLOATING_TEXT_OUTLINE_WIDTH);
  28.     }
  29.     dsFloatingText.Release();
  30.     FLOATING_TEXT_GUI.BackgroundGraphic = sprtFloatingText.Graphic;
  31.   }
  32. }
  33.  
  34. ...
  35.  
  36. function repeatedly_execute_always()
  37. {
  38.   if (Game.GetLocationName(mouse.x, mouse.y)!=null) {
  39.     SetFloatingText(Game.GetLocationName(mouse.x, mouse.y));
  40.   }
  41. }


Surprise, due to something in my implementation of your function in my own code, the floating text doesn't appear. Putting cursor over trees, cave, quicksand etc. doesn't come up with anything - but this Hotspots are supposed to have descriptive Descriptions.
BUT it does come up for object->lookat, and also for speech (so far) - just a copy of the speechbubble.

Video:
https://redrom.ltd/img/floatingtext1.mp4

Note: When I change the text of the function to THIS (lines 5 and 6):

Code: Adventure Game Studio
  1. ...
  2.     if(!String.IsNullOrEmpty(textContent))
  3.     {
  4.       dsFloatingText.DrawingColor = FLOATING_TEXT_COLOR;
  5.       dsFloatingText.drawStringWrappedOutline(683,    //1366/2 pixels left - dead centre
  6.                                               15,     //15 pixels down
  7.                                               FLOATING_TEXT_GUI.Width - 2*FLOATING_TEXT_OUTLINE_WIDTH,
  8.                                               eTextOutlineRounded,
  9.                                               FLOATING_TEXT_FONT,
  10.                                               eAlignCentre,
  11.                                               textContent,
  12.                                               0,
  13.                                               FLOATING_TEXT_OUTLINE_COLOR,
  14.                                               FLOATING_TEXT_OUTLINE_WIDTH);
  15.     }
  16.     dsFloatingText.Release();
  17. ...

to try and position the floating text in the dead centre, the first error is gone, though now it's copying part of the DyanmicSprite for the custom dialogue functions:

https://redrom.ltd/img/floatingtext2.mp4


....SO it's a bug in the dynamic sprite used in SetFloatingText(), OR I've just gone and ruined the implementation of your code :D

Snarky

  • Global Moderator
  • Private Insultant
    • Best Innovation Award Winner 2018, for his numerous additions to the AGS open source ecosystem including the new Awards Ceremony client and modules
    • Snarky worked on one or more games that won an AGS Award!
    •  
    • Snarky worked on one or more games that was nominated for an AGS Award!
Re: MODULE: SpeechBubble v0.8.0
« Reply #71 on: 26 Aug 2019, 06:39 »
Does the GUI have an actual label control in it, or you're just referring to the whole thing as a label?

No, it should be empty. The text is drawn onto the GUI background image.

Also changed #define FLOATING_TEXT_FONT eFontfntSpeech from line 5 to eFontSpeech - this way it compiles. Correct usage? Otherwise it won't compile.

Yes, you have to use whatever font name you have set up in the game, of course.

GetLocationName(mouse.x, mouse.y) gets a location's (Hotspot, Object, etc.) 'Description' (in the editor, in Properties window, under Appearance)?

Correct. One of AGS's little naming inconsistencies.

The reason it's not showing up is that you've put these lines…

Code: Adventure Game Studio
  1. String textContent;
  2. DynamicSprite* sprtFloatingText;

… inside of the SetFloatingText() function. They need to be outside of it, so that the variables persist between function calls. That's why I put them outside.

I think that's also why it shows a copy of the SpeechBubble text: right after the SetFloatingText() DynamicSprite gets destroyed, SpeechBubble creates another one, so that gets the same sprite index, which the GUI background has been set to.

Oh, and also, you shouldn't mess with the positioning code. It's set to be centered and top-aligned within the GUI (with margins just wide enough to fit the outline): You're then shifting it half a screen right, which means it'll show up centered around the right edge of the screen. If you want to move the text, you should either choose a different alignment, or simply reposition/resize the GUI it appears on (e.g. moving it 15 pixels down). If the text may sometimes wrap over multiple lines and you want them bottom-aligned, that would require additional logic.
« Last Edit: 26 Aug 2019, 06:52 by Snarky »

bx83

  • Get 'Er Doooooone
Re: MODULE: SpeechBubble v0.8.0
« Reply #72 on: 26 Aug 2019, 08:43 »
Turned the two variables to globals.
Thank you, it works :)

Snarky

  • Global Moderator
  • Private Insultant
    • Best Innovation Award Winner 2018, for his numerous additions to the AGS open source ecosystem including the new Awards Ceremony client and modules
    • Snarky worked on one or more games that won an AGS Award!
    •  
    • Snarky worked on one or more games that was nominated for an AGS Award!
Re: MODULE: SpeechBubble v0.8.0
« Reply #73 on: 26 Aug 2019, 12:51 »
Glad you got it working!