Legacy:TABname Completion

From Unreal Wiki, The Unreal Engine Documentation Site
Jump to navigation Jump to search

TABname Completion mimics that uncommonly-known mIRC command that fills in a person's name, depending on what text they enter (when you press the TAB key).

This code is/will be in a version of Esc sometime soon – I have placed this in my UTConsole class, in the 'Typing' state, under the 'KeyEvent' function. When entering part of any Player's name (case-sensitive), it will complete the Player's name.

To Do

  • Thanks to Mychaeel's code, it now cycles through similar names. And it works perfectly - no-one prove me wrong.

Implementation

The following implementation in UnrealScript has been created by DJPaul and Mychaeel for the Esc mod. Feel free to use and modify.

<uscript> state Typing {

   //Process 'String' from right-to-left, looking for the first 'LookFor'.
   function int FindRightMost(string String, string LookFor)
   {
       local int i;
       for (i=len(String)-1; i>=0; i--)
       {
           if ( mid(String, i, 1) == LookFor )
           {
               return i+1;
           }
       }
       //Rogue-value.
       return 667;
   }
   event bool KeyEvent( EInputKey Key, EInputAction Action, FLOAT Delta )
   {
       local string TextNameCompletedFirst, TextNameCompletedSuccessor;
       local string ThisPlayerName; //To cut down on long statements below.
       local int RightSpace, i;


       if (Action!=IST_Press)
           return false;
       if ((Key == IK_Tab) && (Viewport.Actor != none))
       {
           // String comparisons (equality, alphabetical order) shall be case-insensitive.
           // Use ~= for equality and Caps() for alphabetical order in UnrealScript.
           RightSpace = FindRightMost(TypedStr, " ");
           if (RightSpace == 667)
               return false;
           if (TextNamePrefix == "")
           {
               TextNamePrefix = Right(TypedStr, len(TypedStr)-RightSpace);
               TextNameCompletedPrev = "";
           }
           if (Viewport.Actor.GameReplicationInfo != none)
           {
               for (i=0; i<32; i++)
               {
                   if (Viewport.Actor.GameReplicationInfo.PRIArray[i] != none)
                   {
                       ThisPlayerName = Viewport.Actor.GameReplicationInfo.PRIArray[i].PlayerName;
                       if (left(ThisPlayerName, len(TextNamePrefix)) == TextNamePrefix)
                       {
                           // Save the first matching player name in alphabetical order in case we don't
                           // find an alphabetical successor of TextNameCompletedPrev.
                           if ((TextNameCompletedFirst == "") || (ThisPlayerName < TextNameCompletedFirst))
                               TextNameCompletedFirst = ThisPlayerName;
                           if (TextNameCompletedPrev != "")
                           {
                               // Save the player name we're looking at if it is one of TextNameCompletedPrev's
                               // alphabetical successors (and a better match than the last one we found).
                               if (ThisPlayerName > TextNameCompletedPrev)
                                   if ((TextNameCompletedSuccessor == "") || (ThisPlayerName < TextNameCompletedSuccessor))
                                       TextNameCompletedSuccessor = ThisPlayerName;
                           }
                       }
                   }
               }
               if (TextNameCompletedSuccessor == "")                     // no alphabetical successor found?
                   TextNameCompletedSuccessor = TextNameCompletedFirst;  // start over from first
               TextNameCompletedPrev = TextNameCompletedSuccessor;     // save for next iteration
               // TextNameCompletedSuccessor now contains the next matching name. Replace the
               // partially entered name by the content of TextNameCompletedSuccessor.
               TypedStr = left(TypedStr, (RightSpace-1)) $ " " $ TextNameCompletedSuccessor;
               return true;
           }
           else
           {
               return false;
           }
       }
       else
       {
           TextNamePrefix = ""; //Make code reevaluate the entered prefix.
           return Super.KeyEvent(Key, Action, Delta);
       }
   }

} </uscript>


Mychaeel: Wouldn't you like case-insensitivity for that? (That's why I mentioned a ~= b and Caps(a) < Caps(b) in that comment – it would be handy.)

DJPaul: Good point - will make it so that it converts them both to uppercase first, just as easy as using a ~# b. I'll upload the tested code this evening.

Mychaeel: ~= strikes me as more elegant (and more concise), that's all. After all its express purpose is to compare strings without case sensitivity.

xX)(Xx: Clearer instructions for where to place the code would be nice ;) or if anyone has the time, a proper .u file, as this is something which a lot of the UT community will want

DJPaul: This went into Esc, a UT1998 mod. IIRC, I put it into our custom Console class. As to where you want it to go, if it's in a dialogue box, you're going to want to do put it in the equivalent of a onKeyEvent method. If you want it from the "T"alk line, you're going to have to replace the class that is done in; I don't know if this is still in Console, I never looked.

El Muerte: it's ExtendedConsole for UT200x. Btw, UT1998 mod? I hope you mean UT'99 ;) My UTelAdSE and UnGateway mods also have tab completion to complete commands, but it works more like the Bash shell (prints a list of available options).

xX)(Xx: Will this work server side? Or will the latest anti-cheats scream HACK! ? ;)

EricBlade: I had to change all occurences of "Viewport" to "ViewportOwner", and add "local string TextNamePrefix, TextNameCompletedPrev;" to the KeyEvent function


----

Category ... erm. Useful Function? Function? Snippet? something, anyway