I've made a recursive function that stores all the players into an array by userid, then lists them on a panel in order depending on their team. This way, all players in the game are shown on a panel listed from longest play time to least, top to bottom. The situation I'm having is that it only shows the LAST player in the respective team on the panel (for 3 teams, only shows 3 players on the panel, I don't know why).
Spoiler
PHP Code:
/* Clear all array entries then refresh them OnClientPutInServer, this is the only time the array should theoretically be organized, clear the proper array entry OnClientDisconnect, when reading from the array to display the list on the panel, ignore 0 value entries (it means client is no longer in game, as thus entry should be ignored) */ /* https://wiki.alliedmods.net/Format_Class_Functions_%28SourceMod_Scripting%29#Advanced_Formatting will help with adding buffers to strings to always make them the same length */
#pragma semicolon 1
#define CLIENTLIMIT 16 /* Real player limit */ #define TEAM_SPC 1 #define TEAM_SUR 2 #define TEAM_INF 3 #define NAME_DRAW_LENGTH 18 /* Actual name size + null terminator, was 17+1 */
new bool:bFirstPass = false; /* Used to determine whether any names have already been added to the large team-name strings */
public Plugin:myinfo = { name = "Ordered Player Panel", author = "Me", description = "Shows a list of all connected players in the game ordered by the player's total time in server since connection (ordered by userid) on a neat panel.", version = "0.0.1", url = "" }
public APLRes:AskPluginLoad2(Handle:hPlugin, bool:bLateLoad, String:sError[], vErrorLength) { // Plugin checked for late loading and ensuring it can only be ran on L4D1 if(IsL4DGame() == false){ strcopy(sError, vErrorLength, "'Ordered Player Panel' was created for L4D1 only.");
return APLRes_Failure; }
return APLRes_Success; }
public OnPluginStart() { RegConsoleCmd("sm_opp", Command_OrderedPlayerPanel, "Initiates the panel for 60 seconds total, automatically shuts off if a drastic event happens (such as round ending).", FCVAR_PLUGIN); }
public Action:Command_OrderedPlayerPanel(vClient, vArgs) { /* Shows the panel to the player for a limited amount of time, definite time dependant on a few factors, in the case of the ordered players array state being changed faster than 0.5s, only allow it to update that fast */ new aPlayersToOrder[MAXPLAYERS+1]; /* Total players available on an SRCDS server + player index shift, since player index's start at 1 and not 0 */
new vWho = 0;
for(vWho = 1; vWho <= MaxClients; vWho++) { /* Looping through all clients, getting their userid, storing that userid into an array */ if(IsClientInGame(vWho) == true) aPlayersToOrder[vWho] = GetClientUserId(vWho); }
SortIntegers(aPlayersToOrder, MaxClients, Sort_Ascending); /* Ordering as if array top-down, smallest numbers appear at top in first index, and go larger as the index grows larger */
decl String:sName[NAME_DRAW_LENGTH]; /* Stringed name of each client added to the menu, 17 characters ensures clients with longer names will have the ends omitted so that the panel is always of uniform width */
/* Preparing the panel ready for display by declaring all the team string player lists */ decl String:sPlayersOrderSur[128]; decl String:sPlayersOrderInf[128]; decl String:sPlayersOrderSpc[256]; /* Double the length because double the amount of players may sit on this team */
/* Looping through the array, getting the userid from each index in the array (the array should already be ordered by this point), check for client in game and non-bot, if true search client team and assign them into a player's list string for the specified team (when drawing teamname objects in panel later on, these strings will be called and all the names in the respective player's list team string shown) */ for(new index = 1; index <= MaxClients; index++){ vWho = GetClientOfUserId(aPlayersToOrder[index]);
if(IsClient(vWho) && IsClientInGame(vWho) && !IsFakeClient(vWho)){ decl String:sNameLine[5+NAME_DRAW_LENGTH] = "\n - "; /* Length of string itself + what can be added to it from a client's name, length value was 22+1, or 23 */ GetClientName(vWho, sName, sizeof(sName));
/* Finally, creating all the panel objects, then displaying itself to the client */ hOrderedPlayerPanel = CreatePanel();
/* Titles are already part of the team strings themselves, no need to include them here :) */ DrawPanelText(hOrderedPlayerPanel, sPlayersOrderSur); DrawPanelText(hOrderedPlayerPanel, sPlayersOrderInf); DrawPanelText(hOrderedPlayerPanel, sPlayersOrderSpc); //DrawPanelText(hOrderedPlayerPanel, " "); /* Without this, the spacing between the top of the panel is a line larger than the bottom (AFAIK, exactly 24 characters, the length the panel should always remain) */
This is what I've got now, still does the exact same thing, it makes 0 sense. I'm telling it to add a bunch of newlines followed by names on 1 string, it only partially displays the string on the menu, it's not even logical.
Spoiler
PHP Code:
/* Clear all array entries then refresh them OnClientPutInServer, this is the only time the array should theoretically be organized, clear the proper array entry OnClientDisconnect, when reading from the array to display the list on the panel, ignore 0 value entries (it means client is no longer in game, as thus entry should be ignored) */ /* https://wiki.alliedmods.net/Format_Class_Functions_%28SourceMod_Scripting%29#Advanced_Formatting will help with adding buffers to strings to always make them the same length */
#pragma semicolon 1
#define CLIENTLIMIT 16 /* Real player limit */ #define TEAM_SPC 1 #define TEAM_SUR 2 #define TEAM_INF 3 #define NAME_DRAW_LENGTH 18 /* Actual name size + null terminator, was 17+1 */
new bool:bFirstPass = false; /* Used to determine whether any names have already been added to the large team-name strings */
public Plugin:myinfo = { name = "Ordered Player Panel", author = "Me", description = "Shows a list of all connected players in the game ordered by the player's total time in server since connection (ordered by userid) on a neat panel.", version = "0.0.1", url = "" }
public APLRes:AskPluginLoad2(Handle:hPlugin, bool:bLateLoad, String:sError[], vErrorLength) { // Plugin checked for late loading and ensuring it can only be ran on L4D1 if(IsL4DGame() == false){ strcopy(sError, vErrorLength, "'Ordered Player Panel' was created for L4D1 only.");
return APLRes_Failure; }
return APLRes_Success; }
public OnPluginStart() { RegConsoleCmd("sm_opp", Command_OrderedPlayerPanel, "Initiates the panel for 60 seconds total, automatically shuts off if a drastic event happens (such as round ending).", FCVAR_PLUGIN); }
public Action:Command_OrderedPlayerPanel(vClient, vArgs) { /* Shows the panel to the player for a limited amount of time, definite time dependant on a few factors, in the case of the ordered players array state being changed faster than 0.5s, only allow it to update that fast */ new aPlayersToOrder[MAXPLAYERS+1]; /* Total players available on an SRCDS server + player index shift, since player index's start at 1 and not 0 */
new vWho = 0;
for(vWho = 1; vWho <= MaxClients; vWho++) { /* Looping through all clients, getting their userid, storing that userid into an array */ if(IsClientInGame(vWho) == true) aPlayersToOrder[vWho] = GetClientUserId(vWho); }
SortIntegers(aPlayersToOrder, MaxClients, Sort_Ascending); /* Ordering as if array top-down, smallest numbers appear at top in first index, and go larger as the index grows larger */
new String:sName[NAME_DRAW_LENGTH]; /* Stringed name of each client added to the menu, 17 characters ensures clients with longer names will have the ends omitted so that the panel is always of uniform width */
/* Preparing the panel ready for display by declaring all the team string player lists */ new String:sPlayersOrderSur[128]; new String:sPlayersOrderInf[128]; new String:sPlayersOrderSpc[256]; /* Double the length because double the amount of players may sit on this team */
new vSur = 0; new vInf = 0; new vSpc = 0;
/* Looping through the array, getting the userid from each index in the array (the array should already be ordered by this point), check for client in game and non-bot, if true search client team and assign them into a player's list string for the specified team (when drawing teamname objects in panel later on, these strings will be called and all the names in the respective player's list team string shown) */ for(new index = 1; index <= MaxClients; index++){ vWho = GetClientOfUserId(aPlayersToOrder[index]);
new String:sNameLine[5+NAME_DRAW_LENGTH] = "\n - "; /* Length of string itself + what can be added to it from a client's name, length value was 22+1, or 23 */ GetClientName(vWho, sName, sizeof(sName)); StrCat(sNameLine, sizeof(sNameLine), sName);
/* Finally, creating all the panel objects, then displaying itself to the client */ hOrderedPlayerPanel = CreatePanel();
/* Titles are already part of the team strings themselves, no need to include them here :) */ DrawPanelText(hOrderedPlayerPanel, sPlayersOrderSur); DrawPanelText(hOrderedPlayerPanel, sPlayersOrderInf); DrawPanelText(hOrderedPlayerPanel, sPlayersOrderSpc); //DrawPanelText(hOrderedPlayerPanel, " "); /* Without this, the spacing between the top of the panel is a line larger than the bottom (AFAIK, exactly 24 characters, the length the panel should always remain) */
Only thing different is the for loop, changed slightly. Literally. Makes no sense.
Edit: Sorry, I put an additional StrCat after the teamname StrCat, and somehow it now works... (I know it was wrong before, but it should've only omitted the first player's name, not the first three...)
If your aim is only to group the players (i.e. ordering by time is just a happy bonus) then you could use something like this. Or at least take parts form it, to integrate into your own to incorporate the player duration too:
new iTeamOrder[3] = { 2, 3, 1 };
new String:szTeamNames[3][4] = { "SUR", "INV", "SPC" }, String:szPanelItem[MAX_NAME_LENGTH + 3];
//In function
new Handle:hOrderedPlayerPanel = CreatePanel();
for (new iTeamIndex = 0; iTeamIndex < sizeof(iTeamOrder); iTeamIndex++)
{
if (GetTeamClientCount(iTeamOrder[iTeamIndex]) < 1) continue;
DrawPanelText(hOrderedPlayerPanel, szTeamNames[iTeamIndex]);
for (new i = 1; i <= MaxClients; i++)
{
if (IsClientInGame(i) && !IsFakeClient(i) && GetClientTeam(i) == iTeamOrder[iTeamIndex])
{
FormatEx(szPanelItem, sizeof(szPanelItem), " - %N", i);
DrawPanelText(hOrderedPlayerPanel, szPanelItem);
}
}
}
SendPanelToClient(hOrderedPlayerPanel, vClient, Panel_OrderedPlayerPanel, 60);