Game Development Community

dev|Pro Game Development Curriculum

1. MXG Gui Mod - Fading Chat

by Marcus L · 10/20/2010 (7:44 pm) · 4 comments

Tested on: 1.1b2 but i expect it to work for all versions

This resource will make your ChatHud(GuiMessageVectorCtrl) able to fade over a certain amount of inactivity. After reading books and internet articles it seems the player usually prefers a GUI that does not confuse or overload their capacity of accepted elements on-screen at the same time. This gets you one step closer to achieve this.

This is how to install this resource same as before:
Where it says // Added, it means that the line is added.
Where it says // Removed, it means that the line is removed.
Where it says // Changed, it means that the line is changed.
Where it says ..., it means that there is code between what ever that was last written.
Whenever it says ..., there will be an comment below describing what function it is.

I recommend you using CTRL + F to find where to put the code blocks. Remember to backup before installing.

First, engine-side, we start by editing gui/game/guiMessageVectorCtrl.cpp:
...
// In GuiMessageVectorCtrl::GuiMessageVectorCtrl()
   for (U32 i = 0; i < 16; i++)
      mAllowedMatches[i] = "";
   mSpecialColor.set(0, 0, 255);

   // Added ->
   mFade = true;
   mTimeActive = 0;
   mFadeStart = 32;
   mAlpha = 0;
   // Added <-
...
// In GuiMessageVectorCtrl::initPersistFields()
   addField("matchColor",         TypeColorI, Offset(mSpecialColor,           GuiMessageVectorCtrl));
   addField("maxColorIndex",      TypeS32,    Offset(mMaxColorIndex,          GuiMessageVectorCtrl));
   addField("startFade",		  TypeF32,    Offset(mFadeStart,			  GuiMessageVectorCtrl)); // Added
...
// In GuiMessageVectorCtrl::onRender(Point2I offset, const RectI& updateRect)
   Parent::onRender(offset, updateRect);
   GFXDrawUtil *drawer = GFX->getDrawUtil();

   if (isAttached())
   {
	   // Added ->
	   // Init colors
	   ColorI defColor = mProfile->mFontColor; // Font color
	   ColorI lastColor = mProfile->mFontColor; // Last color
	   ColorI specialColor = mSpecialColor; // Special color
	   ColorI colors[10];

	   // Add colored text
	   for(S32 i = 0; i < mMaxColorIndex; i++)
	   {
		   if(mProfile->mFontColors[i] == NULL)
			   return;
		   
		   colors[i] = mProfile->mFontColors[i];
	   }

	   // If fade is set to true
	   if(mFade)
	   {
		   // If 32 ticks (1024ms) has
		   // passed, fade out
		   if(mTimeActive >= mFadeStart)
		   {
			   // If alpha is not
			   // transparent already
			   if(mAlpha >= 1)
				   mAlpha -= 1.0f; // Add more transparency
		   }else{
			   // Else add an tick
			   mTimeActive++;
		   }
		   
	   }else{
		   // Set alpha to
		   // visible (255)
		   mAlpha = 255;
		   mTimeActive = 0; // Reset timer
	   }

	   // Asign the current alpha
	   // to the color
	   defColor.alpha = mAlpha;
	   lastColor.alpha = mAlpha;
	   specialColor.alpha = mAlpha;

	   for(S32 i = 0; i < mMaxColorIndex; i++)
	   {
		   if(mProfile->mFontColors[i] == NULL)
			   return;
		   
		   colors[i].alpha = mAlpha;
	   }
	   // Added <-
...
// Same
      for (U32 i = 0; i < mMessageVector->getNumLines(); i++) {
         TextElement* pElement = mLineElements[i].headLineElements;
         ColorI lastColor = mProfile->mFontColor; // Remove
...
// Same
if (walkAcross->specialReference == -1) {
                  drawer->setBitmapModulation(lastColor);
                  drawer->setTextAnchorColor(defColor); // Changed
                  //MXG: This is the colored-text trouble line
                  strWidth = drawer->drawTextN(mProfile->mFont, globalStart, &mMessageVector->getLine(i).message[walkAcross->start],
                                          walkAcross->end - walkAcross->start + 1, colors, mMaxColorIndex); // Changed
               } else {
                  drawer->getBitmapModulation( &lastColor );
                  drawer->setBitmapModulation(specialColor); // Changed
                  drawer->setTextAnchorColor(defColor); // Changed
                  strWidth = drawer->drawTextN(mProfile->mFont, globalStart, &mMessageVector->getLine(i).message[walkAcross->start],
                                          walkAcross->end - walkAcross->start + 1);
...
// Same
                  lineEnd.y += mProfile->mFont->getBaseline() + 1;

                  drawer->drawLine(localToGlobalCoord(lineStart),
                              localToGlobalCoord(lineEnd),
                              specialColor); // Changed
               }
...
// Custom code, put where ever you want
// Added ->
DefineEngineMethod( GuiMessageVectorCtrl, setFade, void, (bool fade),,
				   "@brief Sets the current active state.n"
				   "used for fading out.nn"
				   "@param bool(active)n")
{
	object->setFade(fade);
}

//--------------------------------------------------------------------------
void GuiMessageVectorCtrl::setFade(bool fade)
{
   mFade = fade;
}
// Added <-

Then the header gui/game/guiMessageVector.h:
...
// In protected of class GuiMessageVectorCtrl
   StringTableEntry mAllowedMatches[16];
   ColorI           mSpecialColor;

   // Added ->
   bool mFade;
   F32 mTimeActive;
   F32 mFadeStart;
   F32 mAlpha;
   // Added <-
...
// In public of class GuiMessageVectorCtrl
   bool attach(MessageVector*);
   void detach();

   void setFade(bool fade); // Added

Compile while we take care of torque script-side stuff.
Open and add the following in scripts/client/chatHud.cs:
...
// In onChatMessage(%message, %voice, %pitch)
   // Chat goes to the chat HUD.
   if (getWordCount(%message)) {
      ChatHud.addLine(%message);
   }
   
   // Added ->
   // Show the chat hud
   ChatHud.setFade(false);
   ChatHud.schedule(1000, "checkFade"); // Note: This will add 1 second to the fade
   // Added <-
...
// In ChatHud::addLine(%this,%text)
   else
      chatPageDown.setVisible(false);
      
   %this.setFade(true); // Added
...
// In ChatHud::pageUp(%this)
   // Display the pageup icon
   chatPageDown.setVisible(true);
   
   %this.setFade(false); // Added
...
// In ChatHud::pageDown(%this)
   // See if we have should (still) display the pagedown icon
   if (%scrollLines < %linesToScroll)
      chatPageDown.setVisible(true);
   else // Changed ->
   { 
      chatPageDown.setVisible(false);
      %this.setFade(true); 
   }
   // Changed <-
...
// Custom code, put where ever you want
// Added ->
function ChatHud::checkFade(%this)
{
   // Check if the chat type
   // field is open again
   if(!MessageHud.visible)
      %this.setFade(true);
}
// Added <-

Then edit scripts/client/messageHud.cs
...
// In MessageHud::open(%this)
   deactivateKeyboard();
   MessageHud_Edit.makeFirstResponder(true);
   
   ChatHud.setFade(false); // Added
...
// In MessageHud::close(%this)
   if ( $enableDirectInput )
      activateKeyboard();
   MessageHud_Edit.setValue("");
   
   ChatHud.setFade(true); // Added

Now, replace the ChatHudMessageProfile in art/gui/defaultGameProfiles.cs:
...
// In singleton GuiControlProfile ("ChatHudMessageProfile")
// Changed ->
singleton GuiControlProfile ("ChatHudMessageProfile")
{
   opaque = true;
   fillColor = "0 0 0 0";
   
   fontType = "Arial";
   fontSize = 16;
   fontColor = "44 172 181 0";    // default color (death msgs, scoring, inventory)
   fontColors[1] = "4 235 105";   // client join/drop, tournament mode
   fontColors[2] = "219 200 128"; // gameplay, admin/voting, pack/deployable
   fontColors[3] = "77 253 95";   // team chat, spam protection message, client tasks
   fontColors[4] = "40 231 240";  // global chat
   fontColors[5] = "200 200 50 200";  // used in single player game
   
   // WARNING! Colors 6-9 are reserved for name coloring
   autoSizeWidth = true;
   autoSizeHeight = true;
};
// Changed <-

Last, remove the gray overlay control of the chat hud NOTE: this step is not required, but the frame doesn't fade,
replace art/gui/chatHud.gui:
//-----------------------------------------------------------------------------
// Chat edit window
//-----------------------------------------------------------------------------

new GuiControl(MessageHud)
{
   profile = "GuiDefaultProfile";
   horizSizing = "width";
   vertSizing = "height";
   position = "0 0";
   extent = "640 480";
   minExtent = "8 8";
   visible = "0";
   noCursor = true;

   new GuiBitmapBorderCtrl(MessageHud_Frame) {
      profile = "ChatHudBorderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "120 375";
      extent = "400 40";
      minExtent = "8 8";
      visible = "1";

      new GuiBitmapCtrl() {
         profile = "GuiDefaultProfile";
         horizSizing = "width";
         vertSizing = "height";
         position = "8 8";
         extent = "384 24";
         minExtent = "8 8";
         visible = "1";
         helpTag = "0";
         bitmap = "core/art/gui/images/hudfill.png";
         wrap = "0";
      };

      new GuiTextCtrl(MessageHud_Text)
      {
         profile = "ChatHudTextProfile";
         horizSizing = "right";
         vertSizing = "bottom";
         position = "14 12";
         extent = "10 22";
         minExtent = "8 8";
         visible = "1";
      };

      new GuiTextEditCtrl(MessageHud_Edit)
      {
         profile = "ChatHudEditProfile";
         horizSizing = "right";
         vertSizing = "bottom";
         position = "0 13";
         extent = "10 22";
         minExtent = "8 8";
         visible = "1";
         altCommand = "$ThisControl.eval();";
         escapeCommand = "MessageHud_Edit.onEscape();";
         historySize = "5";
         maxLength = "120";
      };
   };
};
//--- OBJECT WRITE BEGIN ---
%guiContent = new GuiControl(MainChatHud) {
   position = "0 0";
   extent = "1024 768";
   minExtent = "8 8";
   horizSizing = "width";
   vertSizing = "height";
   profile = "GuiModelessDialogProfile";
   visible = "1";
   active = "1";
   tooltipProfile = "GuiToolTipProfile";
   hovertime = "1000";
   isContainer = "1";
   canSave = "1";
   canSaveDynamicFields = "1";
      helpTag = "0";
      noCursor = "1";

   new GuiControl() {
      position = "0 0";
      extent = "640 300";
      minExtent = "8 8";
      horizSizing = "relative";
      vertSizing = "bottom";
      profile = "GuiModelessDialogProfile";
      visible = "1";
      active = "1";
      tooltipProfile = "GuiToolTipProfile";
      hovertime = "1000";
      isContainer = "1";
      canSave = "1";
      canSaveDynamicFields = "0";

      new GuiBitmapBorderCtrl(OuterChatHud) {
         position = "0 0";
         extent = "512 160";
         minExtent = "8 8";
         horizSizing = "width";
         vertSizing = "bottom";
         profile = "GuiDefaultProfile";
         visible = "1";
         active = "1";
         tooltipProfile = "GuiToolTipProfile";
         hovertime = "1000";
         isContainer = "0";
         canSave = "1";
         canSaveDynamicFields = "0";

         new GuiButtonCtrl(chatPageDown) {
            text = "Dwn";
            groupNum = "-1";
            buttonType = "PushButton";
            useMouseEvents = "0";
            position = "460 130";
            extent = "36 14";
            minExtent = "8 8";
            horizSizing = "left";
            vertSizing = "top";
            profile = "GuiButtonProfile";
            visible = "0";
            active = "1";
            tooltipProfile = "GuiToolTipProfile";
            hovertime = "1000";
            isContainer = "0";
            hidden = "1";
            canSave = "1";
            canSaveDynamicFields = "0";
         };
         new GuiScrollCtrl(ChatScrollHud) {
            willFirstRespond = "1";
            hScrollBar = "alwaysOff";
            vScrollBar = "alwaysOff";
            lockHorizScroll = "1";
            lockVertScroll = "0";
            constantThumbHeight = "0";
            childMargin = "0 0";
            mouseWheelScrollSpeed = "-1";
            margin = "0 0 0 0";
            padding = "0 0 0 0";
            anchorTop = "1";
            anchorBottom = "0";
            anchorLeft = "1";
            anchorRight = "0";
            position = "8 8";
            extent = "496 144";
            minExtent = "8 8";
            horizSizing = "width";
            vertSizing = "height";
            profile = "ChatHudScrollProfile";
            visible = "1";
            active = "1";
            tooltipProfile = "GuiToolTipProfile";
            hovertime = "1000";
            isContainer = "1";
            canSave = "1";
            canSaveDynamicFields = "0";

            new GuiMessageVectorCtrl(ChatHud) {
               lineSpacing = "0";
               lineContinuedIndex = "10";
               allowedMatches[0] = "http://";
               allowedMatches[1] = "tgeserver://";
               allowedMatches[2] = "www.";
               matchColor = "0 0 255 255";
               maxColorIndex = "5";
               startFade = "32";
               position = "0 0";
               extent = "496 88";
               minExtent = "8 8";
               horizSizing = "width";
               vertSizing = "height";
               profile = "ChatHudMessageProfile";
               visible = "1";
               active = "1";
               tooltipProfile = "GuiToolTipProfile";
               hovertime = "1000";
               isContainer = "0";
               canSave = "1";
               canSaveDynamicFields = "0";
            };
         };
      };
   };
};
//--- OBJECT WRITE END ---

Now enter your game and,
"oh, the chat is gone!"
*presses the chat button*
there it is.
*finishes typing*
And it fades.

Also, if you use pageUp/pageDown to scroll, it'll be visible until you scroll back down to the bottom.

Note that I've added a field in the GuiMessageVectorCtrl called startFade which is the time the hud should start to fade. This value is not messured in ms or seconds but by renders. In other words, this might be dynamic.

Known Issues: None :D

BTW. The GUI Mod is just like my Weapon Mod, there will come more, but I'm not sure what or when. So if you have ideas (that are realizable) PM me and I'll see what i can do. Also, my Weapon Mod is not finished, there will keep coming more when that time comes.
I will be around this community for a while, a very long while i believe, so, there will always be more.

Then the usual bottom line:
If you stumble upon some issues, let me know.
Also know that my methods might not be correct, nor the most professional. Therefore if you see some silly mistakes please leave a comment with the "fix".

Other resources in my GUI Mod:
(To Come...)

Thanks,
Marcus L.

#1
10/21/2010 (9:36 am)
Looks like a cool idea Marcus.
#2
11/11/2010 (4:33 pm)
Nifty. I'd use it if it would support colored text. Looking forward to updates!
#3
11/15/2010 (11:28 pm)
If so, I'll look into adding colored text ASAP! Just had to know someone would actually need it :P
#4
11/18/2010 (6:56 pm)
There! Updated the original resource, now fades colored text.

@JulianR
Thank you, even tho (i believe) many commercial games already use this technique. Just sayin'