TABname Completion
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.
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); } } }
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.
Category ... erm. Useful Function? Function? Snippet? something, anyway