Improved Chat Messages

From Oldunreal-Wiki
Jump to navigation Jump to search

This little tutorial goes over how to override the Say (and TeamSay) functions found in the PlayerPawn code to let players use escape codes in their messages to relay information. To make everything nice and neat I just went ahead and created a new function ParseChatString that will take a message, parse it, modify it as necessary, and then return the modified message. Then I made new versions of Say and TeamSay that call my new function to modify their message and then send/display the modified message. So in theory all you would have to do to integrate this code into your modification would be to put these 3 functions inside of your new PlayerPawn subclass.

ParseChatString takes a message, then steps through it one character at a time looking for the escape character #. Once it finds the escape character it grabs the next character then inserts whatever data into a new modified message, and then continues on parsing looking for more escape sequences until the end of the string is reached, and finally it returns the modified message.

// function string ParseChatString(string Msg)
// escape codes:
// =============
// #N - player name
// #L - player location
// #S - player status (health/armor)
// #H - player health
// #A - player armor
// #B - buddies, lists friendly players within radius
// #W - player weapon
// #T - test code
// ## - print the '#' character
// The buddy code uses RadiusActors to find pawns, and then checks to make
// sure they are on the same team, if so adds them to the buddy list (bStr),
// then when its done goes back and rewrites bStr to be grammatically correct,
// i.e. it adds an "and" etc etc.  I know, its a waste of time, but I got
// a kick out of the fact that it worked the first time. :)
// To add more codes just add more cases in the switch statement, and append
// the information onto nMsg.
// TODO:
// - maybe add multiple levels of escape codes, like #b:5 would return 5 buddies?
function string ParseChatString(string Msg)
  local int i, amt, numBuddy, lBuddyLen;
  local float BuddyRadius;
  local string nMsg, tStr, bStr, lbStr;
  local Inventory Inv;
  local Pawn Buddy;
  local PlayerReplicationInfo mPRI, bPRI;
  BuddyRadius = 1500.0;
  mPRI = PlayerReplicationInfo;
  // step through the string and look for escape char
  // Len(string) returns the length of the string
  for (i = 0;i <= Len(Msg);i++)
    // use mid to get the char at i in Msg since Msg[i] doesn't work
    // Mid(string, pos, count) returns a string starting at pos and
    // ending at pos+count, so to get one char we use a count of 1
    if (Mid(Msg, i, 1) == "#")
      // found escape char, now get the next char and parse
      i += 1;
      tStr = Mid(Msg,i,1);
      // this is our main switch statement, to add more escape codes
      // just add more cases in here
      switch (tStr)
        // player weapon - inserts weapon name
        case "W":
          nMsg = nMsg $ Weapon.ItemName;
        // player name - inserts this player's name
        case "N":
          nMsg = nMsg $ mPRI.PlayerName;
        // player location - inserts the player's location
        case "L":
          if (mPRI.PlayerLocation != NONE)
            nMsg = nMsg $ mPRI.PlayerLocation.LocationName;
          else if (mPRI.PlayerZone != NONE)
            nMsg = nMsg $ mPRI.PlayerZone.ZoneName;
          else nMsg = nMsg $ "somewhere";
        // player armor - inserts player's armor count
        case "A":
          amt = 0;
          for (Inv = Inventory; Inv != NONE; Inv = Inv.Inventory)
            if (Inv.bIsAnArmor)
              amt += Inv.Charge;
          nMsg = nMsg $ amt;
        // player health - inserts player's health
        case "H":
          nMsg = nMsg $ Health;
        // player status - inserts health & armor
        case "S":
          amt = 0;
          for (Inv = Inventory; Inv != NONE; Inv = Inv.Inventory)
            if (Inv.bIsAnArmor)
              amt += Inv.Charge;
          nMsg = nMsg $ "Health: " $ Health $ " Armor: " $ amt;
        // player buddies - inserts a list of friendly units within
        // a defined radius
        case "B":
          numBuddy = 0;
          foreach RadiusActors(class'Pawn', Buddy, BuddyRadius)
            bPRI = Buddy.PlayerReplicationInfo;
            if (Buddy != Self && Buddy.bIsPlayer && bPRI.Team == mPRI.Team)
              lbStr = bPRI.PlayerName;
              lBuddyLen = Len(lbStr);
              if (numBuddy < 1)
                bStr = lbStr;
              else bStr = bStr $ ", " $ lbStr;
          // backtrack a bit and add an "and" to the message if
          // we had 2 or more buddies, to be grammatically correct
          if (numBuddy >= 3)
            bStr = Left(bStr, Len(bStr) - lBuddyLen) $ " and " $ lbStr;
          else if (numBuddy == 2)
            bStr = Left(bStr, Len(bStr) - lBuddyLen - 2) $ " and " $ lbStr;
          else if (numBuddy == 0)
            bStr = "nobody";
          nMsg = nMsg $ bStr;
        // test - just a test to play around with
        case "T":
          nMsg = nMsg $ "<test>";
        // print the '#' character
        case "#":
          nMsg = nMsg $ "#";
    // if we didn't find an escape code just copy char straight over
    // to the new message
    else nMsg = nMsg $ Mid(Msg, i, 1);
  // and finally return the new message
  return nMsg;

Now all that's left is to change the Say and TeamSay functions to call the new ParseChatString function, and then call the original Say and TeamSay functions with the new message to be sent/displayed.

exec function Say( string Msg )
  // parse the chat string
  Msg = ParseChatString(Msg);
  // and send up our new and improved message
exec function TeamSay(string Msg)
  // parse the chat string
  Msg = ParseChatString(Msg);
  // and send up our new and improved message

And that's that. If you want to use this you must put it in a new PlayerPawn subclass and then change your ut.ini or make a new gametype to make sure you spawn as that new class...but thats beyond the scope of this tutorial.