[ News | About | Media | Downloads | Tutorials | Contact ]


Latest News | Previous Article | Next Article

11 December 2011 - Speech Bubbles

Mod of the Year Awards Today we are releasing the source code for the speech bubbles. We are not planning to release the whole source code for Water, atleast not yet, but if you have wishes to know how some certain parts of Water were made, let us know.

The speech bubbles in Water are completely generated by the HUD. The size of the bubble is calculated by how long the text is. They also support localization, to allow them to be translated to any language.

Don't forget to read Making Of Water:
You can also now download the remastered Water soundtrack by Dennis "Entru" Yaremov. But I digress, the speech bubbles:

Speech Bubbles

Setting it up

First you can download the four C++ files:

mm_hud_speech_bubbles.h and mm_hud_speech_bubbles.cpp are for the client side while util_speech_bubble.cpp is for the server side, and hlss_speech_bubbles_shared.h is shared.

You need to add add "StartBubble" and "NarrationBox" to your hl2_usermessages.cpp.
	usermessages->Register( "SpeechBubble", -1 );
	usermessages->Register( "NarrationBox", -1 );
You also need to download the materials:

They need to go to materials\vgui\ subfolder of your mod.

You need to add the speech bubble hud element to HudLayout.res in the script subfolder of your mod. Add this somewhere in the file.
		"fieldName"		"HudSpeechBubble"
		"wide"	"640"
		"tall"  "480"
		"visible" "1"
		"enabled" "1"

For localization, you can either add your lines to your existing mod localization file which is [modname]_english.txt for english language users. Or you can create a seperate localization file for all the speech bubbles. If you have your own localization file you need to add it to the localization system either in the speech bubbles hud element or somewhere like in VGui_Startup function in vgui_int.cpp.

Finally you need to define what fonts you want to use for the bubble text. You can either edit mm_hud_speech_bubbles.h so that it uses some entries from ClientScheme.Res in the resource subfolder of your mod.
	CPanelAnimationVar( vgui::HFont, m_hTextFont, "TextFont", "HLSS_SpeechBubble" );
	CPanelAnimationVar( vgui::HFont, m_hKeyFont, "KeyFont", "HLSS_SpeechBubbleKey" );
Or you can edit the ClientScheme.Res and add the fonts we used into the Fonts section:
				"name"		"Georgia"
				"tall"		"9"
				"weight"	"700"
				"antialias" "1"
				"name"		"Georgia"
				"tall"		"9"
				"weight"	"700"
				"dropshadow"	"1"

How to use the bubbles

On the server side you have the four functions. You have two for the speech bubbles, and two for the narration boxes. Include hlss_speech_bubbles_shared.h to any file where you want to use the speech bubbles in.
  void UTIL_SpeechBubble( CBasePlayer *pPlayer, 
			  CBaseAnimating *pSpeaker, 
			  const char *strBubble, 
			  float flDelay = 5.0f,
			  int iPriority = BUBBLE_PRIORITY_VERY_LOW,
			  int iAttachment = -1 );
  void UTIL_StopBubble( CBasePlayer *pPlayer, CBaseAnimating *pSpeaker );
  void UTIL_NarrationBox( CBasePlayer *pPlayer, 
			  const char *strBubble, 
			  float flDelay, 
			  bool bAbsolute = false, 
			  float xratio = 0.5, 
			  float yratio = 0.5 );
  void UTIL_ClearNarrationBoxes( CBasePlayer *pPlayer );

So, to show a simple speech bubble on an NPC's head you call UTIL_SpeechBubble. The first variable is the player you want to send the bubble. If the pointer is NULL it will use the PAS filter. If your mod is a multiplayer, this might be useful since it would send it to all players who are in the proximity of the speaking entity. However, since Water was a single player mod, I didn't add an option to send the bubble to all players no matter where they are in the map. If the pointer is defined, it will send the bubble only to that player.

Next is the pointer to the speaker entity. This can be something like an NPC or the player themselves. The bubble will appear on that NPC. The attachment option defines where from the character's body the bubble's tail is coming from. Usually you want to use the "mouth" attachment, which would mean calling pSpeaker->LookupAttachment( "mouth" ). Each entity can only show one speech bubble at once, and if the entity is already showing a speech bubble, the new will either replace that one, or not show up at all.

The strBubble option should usually be a localization token refering to an entry in a localization file. You can use unlocalized lines here as well, but it is recommended you use localization. The delay determines how long the bubble should appear on the screen. In Water using the delay of 0, would make the game wait until the player has pressed a key to skip it. Since I don't cover how to make a dialogue selection menu in this tutorial, I have disabled that option for now.

The priority option tells the system how important the bubble is. If the entity the bubble is supposed to be shown on is already showing a speech bubble, and the old speech bubble has higher priority than the new one, the new one wont replace the old one. Bubbles with higher or equal priority of Medium, are also always shown, even if the entity is off screen.

How it works

You don't necessarily need to read this if you want to add the bubbles to your mod, but it helps if you want to change something in their behavior. I only cover bubbles here, but the narration boxes work pretty much the same. Since this tutorial doesn't cover how to make a dialogue selection menu either, I have commented out some of the references to it.

In short, first the server side sends a localization token to the client side with info on which entity it wants to show the bubble on and so on. The client side CHudSpeechBubbles HUD element then localizes the file, goes through it cutting it into smaller lines to fit the speech bubble shape, and adds it to the list of all speech bubbles.

The Paint function then paints all the speech bubbles and removes them if necessary.

This is the function you call on the server side to show a speech bubble on the speaker entity. First it creates a filter, which determines which players can see the bubble. If the player pointer is NULL, it will simply use the speaker's center to determine which player's could see it using the PAS filter.

It then starts sending the usermessage SpeechBubble (as declared in hl2_usermessage.cpp) to the client. The HLSS_MESSAGE_SPEECH_BUBBLE macro defines the message. It starts by writing the entity index of the speaker entity, which will used to find the entity on the client side. After that it will send the bubble delay, priority, the token for the bubble, and the attachment index.

This is the first thing that gets called on the client side. It goes through the data the server side sent, and follows the same message structure. It uses the entity index to find the pointer to the speaker entity. If the delay is negative it assumes it's supposed to remove any speech bubble from the entity rather than add a new one, and after doing so, it will stop reading the message. Other wise it will continue reading the message, and priority, token and the attachment.

It then tries to localize the token into a wchar_t buffer. If the token is not found in any localization file, it will simply show the token as it is.

If the bubble token has the $number$ character in it, the code tries to replace the number with a random number from 1 to the number before localization. For example, if the localization token sent by the server was #MM_Helper_Ask$3$, it would randomize a number between 1 and 3, so that any of the three versions of the line could show up.
	"MM_Helper_Ask1"	"Hey, toss me that beer, will you?"
	"MM_Helper_Ask2"	"Can I have that beer?"
	"MM_Helper_Ask3"	"Can I please get that beer?"

This function checks if the speaker entity already has a speech bubble, and depending on that, adds a new one to the list of speechbubbles m_vSpeechBubbles, or edits the existing on. After this it calls ProcessLines.

Here the speech bubbles are cut into several lines that are later painted seperately. It also goes through all the text and tries to replace any references to key bindings, and tries to find the name of the key the player has bound to that action. For example, if the bubble has the text %+attack% in it, the code will replace it with the name of the key the player has bound it to, which is by default MOUSE1.

First the function tries to approximate the size of the speech bubble by using it length. It then starts going through the text character by character, trying to figure out how it would fit inside the bubble shape, and cuts the lines as necessary. Finally it adds the fully processed line to the list of all speech bubbles.

Processed Bubble structere
The processed lines are listed in the UtlVector m_vSpeechBubbles, where every bubble is a single struct sSpeechBubble.
  struct sSpeechBubble
	EHANDLE		m_hEnt;
	int			m_iAttachment;
	int			m_iType;

	float		m_flRemoveTime;
	int			m_iAlignment;
	int			m_iPriority;
	int			m_iWide;
	int			m_iTall;
	int			m_iLettersReached;
	float		m_flNextGetLetter;

	CUtlVector<sProcessedBubbleLine>	m_vSpeechBubblesLines;
The EHANDLE m_hEnt is the entity the bubble is shown on. If the handle returns a NULL pointer, it means something has deleted the entity, and the bubble will be deleted as well. m_iAttachment defines, like previously mentioned, where in the model the bubble should appear. m_iType defines what color the bubble should be. As it is, the choices there are kind of limited, so you can add more choices there if you want.

m_iAlingment defines what direction the speech bubble's tail was pointing the last time the speech bubble was painted. m_iLettersReached is how many characters of the bubble should be shown. m_flNextGetLetter is when the next letter should be shown. The UtlVector m_vSpeechBubblesLines is a list of the speech bubbles lines.
  struct sProcessedBubbleLine
  	wchar_t unicode[MAX_SPEECH_BUBBLE_LINE];
	int width;
	int length;
The Paint function goes through all the bubbles and sees which ones it should paint, which ones not, and which ones it should remove. After that it does the same for narration boxes. For both of them it first checks if it should remove any of the bubbles.

With the bubbles it does a couple of things to check if the bubble should be drawn. It checks if the entity is off screen or if the speaker entity is visible. It also checks the distance of the attachment from the main view origin. If the distance is bigger than 1536 the bubble wont get drawn. In Water we didn't want the crabs' idle speech bubbles to be shown if the player was above water, so we also added a check to see if the main view origin is on the other side of the water surface than the attachment position.

The alignment of the bubble depends, if the bubble is near the edges of the screen, and direction the mouth attachment is pointing. The code also takes into consideration the alignment the bubble had previous round, so that the bubble wont suddenly change direction when the attachment moves even slightly.

If you didn't see the release trailer yet, here it is once again:

Release Trailer







Download Water now

If you haven't yet played Water, you can download the installer, or use Desura, or unpack the .zip file to SourceMods so that the mod folder is called "water". You will have to have Source SDK Base 2007 installed on your Steam account. You can install Source SDK Base 2007 by accessing the Tools section in your Games Library. You need to have a Source engine game like Half-Life 2, Counter-Strike Source, or Portal to have Source SDK Base 2007 available.

Additionally if you the version of Water you downloaded is 1.0.2 or lower, download 1.0.3 Patch. The current installer is 1.0.3. If you have any problems with installing the patch, or anything else, go to the Water Bugs & Problems page.

[Comment on Moddb]

by Au-heppa
Permalink: http://hlssmod.net/index.php?page=0&news=25

Hide full article list
52.  Friday Update VIII - 13 May 2016
51.  1 April 2016 - Friday Update III
50.  25 March 2016 - Friday Update II
49.  18 March 2016 - Friday Update I
48.  10 March 2016 - Public Beta Released
47.  28 February 2016 - Public Beta Release Date
46.  31 January 2016 - Public Beta
45.  27 September 2015 - Merging Items
44.  20 September 2015 - Teaser Trailer
43.  13 September 2015 - Custom Items
42.  8 April 2015 - Voice Actors, Streams, and Alien Posters
41.  6 December 2014 - Asi pos Ruumste
40.  22 October 2014 - Steam Greenlight
39.  14 June 2014 - Language Barriers
38.  12 February 2014 - Language System
37.  28 December 2013 - Fighting System
36.  6 June 2013 - Level Designers and a Voice Actress
35.  28 April 2013 - Playtesting From Earth
34.  8 April 2013 - Alien AI
33.  18 March 2013 - From The Darkness
32.  4 March 2013 - Climbing System
31.  4 February 2013 - Interaction System
30.  14 January 2013 - First Person
29.  7 January 2013 - What happened to Human Error?
28.  1 January 2013 - From Earth
27.  15 February 2012 - LAST ZOMBIE
26.  16 December 2011 - World Of Water
25.  11 December 2011 - Speech Bubbles
24.  7 December 2011 - Making Of Water Part III
23.  3 December 2011 - Making Of Water Part II
22.  1 December 2011 - Making Of Water Part I
21.  21 November 2011 - A quick look into the making of a gesture
20.  13 November 2011 - Water Released
19.  6 November 2011 - Water Release Date
18.  30 July 2011 - Human Error Source Code Released
17.  6 January 2011 - First Ever Weapon Render
16.  3 December 2010 - Water
15.  26 November 2010 - Controllable Manhacks
14.  28 July 2010 - Alyx Mode and More
13.  14 July 2010 - Human Error Co-op Beta Released
12.  29 May 2010 - Alien Grunt & Controller Give Away
11.  26 April 2010 - He's a frakking Traitor
10.  8 Feb 2010 - Human Error Released
9.  7 Feb 2010 - This Is Larson
8.  29 Dec 2009 - 2010 Trailer
7.  28 Dec 2009 - Super Secret Beta Testing Blog
6.  17 Nov 2009 - Harder, Better, Faster, Stronger
5.  17 Oct 2009 - This Is Noah
4.  23 Jul 2009 - This Is Embarassing
3.  1 Jul 2009 - This Is Au-heppa
2.  17 Mar 2009 - HLSS in Podcast 17
1.  5 Nov 2008 - First Media Release

[ News | About | Media | Downloads | Tutorials | Contact ]

Valve, the Valve logo, Half-Life, the Half-Life logo, the Lambda logo, Steam, the Steam logo, Source, and the Source logo are trademarks and/or registered trademarks of Valve Software. All information is copyright their respective authors. Website designed by Han Solo.