From 3ba7c63862a2b9f967cd92c0686e440e18bb4d01 Mon Sep 17 00:00:00 2001
From: Matt Woodrow <pred@alliedmods.net>
Date: Mon, 10 Dec 2007 21:02:00 +0000
Subject: [PATCH] Initial import of dynamic menu code (amb1039)

--HG--
branch : sourcemod-1.1.0
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/branches/sourcemod-1.1.0%401788
---
 configs/dynamicmenu/adminmenu_grouping.txt |  18 +
 configs/dynamicmenu/menu.ini               | 390 ++++++++++++++++
 plugins/adminmenu.sp                       |  25 +-
 plugins/adminmenu/dynamicmenu.sp           | 511 +++++++++++++++++++++
 4 files changed, 938 insertions(+), 6 deletions(-)
 create mode 100644 configs/dynamicmenu/adminmenu_grouping.txt
 create mode 100644 configs/dynamicmenu/menu.ini
 create mode 100644 plugins/adminmenu/dynamicmenu.sp

diff --git a/configs/dynamicmenu/adminmenu_grouping.txt b/configs/dynamicmenu/adminmenu_grouping.txt
new file mode 100644
index 00000000..8c391211
--- /dev/null
+++ b/configs/dynamicmenu/adminmenu_grouping.txt
@@ -0,0 +1,18 @@
+/* Add group options to be added to 'group' or 'groupplayer' type submenus
+ * The left side is the name that will show in the menu, right is the command that will be fired
+ */	
+
+Groups
+{
+	"All"			"@all"
+	"Bots"			"@bots"
+	"Alive"			"@alive"
+	"Dead"			"@dead"
+	"Humans"		"@humans"
+	"Current aim"		"@aim"
+
+	/* You can enable these if you are using Counter-Strike Source and running the cstrike extension */
+//	"Terrorists"		"@t"
+//	"Counter-Terrorists"	"@ct"
+
+}
\ No newline at end of file
diff --git a/configs/dynamicmenu/menu.ini b/configs/dynamicmenu/menu.ini
new file mode 100644
index 00000000..c5362199
--- /dev/null
+++ b/configs/dynamicmenu/menu.ini
@@ -0,0 +1,390 @@
+"Commands"
+{
+	"title"		"Choose a Category"
+	"Fun Commands"
+	{
+		"admin"		"sm_ban"
+		"Set Player Speed"
+		{
+			"cmd"			"sm_speed #1 #2"
+			"execute"		"player"
+			"1"
+			{
+				"type" 		"teamplayer"
+				"method"	"name"
+				"title"		"Player/Team to Edit"
+
+			}
+			"2"
+			{
+				"type" 		"list"
+				"title"		"Speed Multiplier"
+				"1"		"1.0"
+				"1."		"Normal"
+				"2"		"0.8"
+				"2."		"80%"
+				"3"		"0.5"
+				"3."		"Half"
+				"4"		"1.5"
+				"4."		"50% Boost"
+				"5"		"2.0"
+				"5."		"Double"
+			}
+
+		}
+		"Give Player Weapon"
+		{
+			"cmd"			"sm_weapon #1 #2"
+			"1"
+			{
+				"type" 		"player"
+				"title"		"Player to Give to"
+
+			}
+			"2"
+			{
+				"type" 		"list"
+				"title"		"Weapon:"
+				"1"		"weapon_ak47"
+				"1."		"Ak-47"
+				"2"		"weapon_m4a1"
+				"2."		"M4A1"
+				"3"		"weapon_deagle"
+				"3."		"Desert Eagle"
+				"4"		"weapon_mp5"
+				"4."		"MP5"
+			}
+
+		}
+		"Set Player Armour"
+		{
+			"cmd"			"sm_armour #1 #2"
+			"execute"		"player"
+			"1"
+			{
+				"type" 		"teamplayer"
+				"method"	"name"
+				"title"		"Player/Team to Edit"
+
+			}
+			"2"
+			{
+				"type" 		"list"
+				"title"		"Armour:"
+				"1"		"0"
+				"2"		"20"
+				"3"		"50"
+				"4"		"80"
+				"5"		"100"
+			}
+
+		}
+		"Set Player HP"
+		{
+			"cmd"			"sm_hp #1 #2"
+			"execute"		"player"
+			"1"
+			{
+				"type" 		"teamplayer"
+				"method"	"name"
+				"title"		"Player/Team to Edit"
+
+			}
+			"2"
+			{
+				"type" 		"list"
+				"title"		"HP:"
+				"1"		"1"
+				"2"		"20"
+				"3"		"50"
+				"4"		"80"
+				"5"		"100"
+				"6"		"150"
+				"7"		"200"
+			}
+
+		}
+		"Bury Player"
+		{
+			"cmd"			"sm_bury #1"
+			"execute"		"player"
+			"1"
+			{
+				"type" 		"teamplayer"
+				"method"	"name"
+				"title"		"Player/Team to Bury"
+
+			}
+		}
+		"UnBury Player"
+		{
+			"cmd"			"sm_unbury #1"
+			"execute"		"player"
+			"1"
+			{
+				"type" 		"teamplayer"
+				"method"	"name"
+				"title"		"Player/Team to UnBury"
+
+			}
+		}
+		"Respawn Player"
+		{
+			"cmd"			"sm_respawn #1"
+			"execute"		"player"
+			"1"
+			{
+				"type" 		"teamplayer"
+				"method"	"name"
+				"title"		"Player/Team to Respawn"
+
+			}
+		}
+		"Disarm Player"
+		{
+			"cmd"			"sm_disarm #1"
+			"execute"		"player"
+			"1"
+			{
+				"type" 		"teamplayer"
+				"method"	"name"
+				"title"		"Player/Team to Disarm"
+
+			}
+		}
+		"Burn and Disarm"
+		{
+			"cmd"			"sm_burn #1 #2;sm_disarm #1"
+			"execute"		"player"
+			"1"
+			{
+				"type" 		"teamplayer"
+				"method"	"name"
+				"title"		"Player/Team to Burn"
+
+			}
+			"2"
+			{
+				"type" 		"list"
+				"title"		"Time:"
+				"1"		"0"
+				"2"		"5"
+				"3"		"10"
+				"4"		"20"
+				"5"		"30"
+			}
+
+		}
+		"Set Player Gravity"
+		{
+			"cmd"			"sm_gravity #1 #2"
+			"execute"		"player"
+			"1"
+			{
+				"type" 		"teamplayer"
+				"method"	"name"
+				"title"		"Player/Team to Edit"
+
+			}
+			"2"
+			{
+				"type" 		"list"
+				"title"		"Speed Multiplier"
+				"1"		"1.0"
+				"1."		"Normal"
+				"2"		"0.8"
+				"2."		"80%"
+				"3"		"0.5"
+				"3."		"Half"
+				"4"		"1.5"
+				"4."		"50% Boost"
+				"5"		"0.25"
+				"5."		"Quarter"
+			}
+
+		}
+		"Set Player No-Clip"
+		{
+			"cmd"			"sm_noclip #1 #2"
+			"1"
+			{
+				"type"		"teamplayer"
+			}
+			"2"
+			{
+				"type"		"list"
+				"1"		"1"
+				"1."		"On"
+				"2"		"0"
+				"2."		"Off"
+			}
+		}
+		"Set Player God"
+		{
+			"cmd"			"sm_god #1 #2"
+			"1"
+			{
+				"type"		"teamplayer"
+			}
+			"2"
+			{
+				"type"		"list"
+				"1"		"1"
+				"1."		"On"
+				"2"		"0"
+				"2."		"Off"
+			}
+		}
+		"Set Player NightVision"
+		{
+			"cmd"			"sm_nv #1 #2"
+			"1"
+			{
+				"type"		"teamplayer"
+			}
+			"2"
+			{
+				"type"		"list"
+				"1"		"1"
+				"1."		"Give"
+				"2"		"0"
+				"2."		"Take"
+			}
+		}
+		"Set Player Helmet"
+		{
+			"cmd"			"sm_helmet #1 #2"
+			"1"
+			{
+				"type"		"teamplayer"
+			}
+			"2"
+			{
+				"type"		"list"
+				"1"		"1"
+				"1."		"Give"
+				"2"		"0"
+				"2."		"Take"
+			}
+		}
+		"Set Player Defuse Kit"
+		{
+			"cmd"			"sm_defuser #1 #2"
+			"1"
+			{
+				"type"		"teamplayer"
+			}
+			"2"
+			{
+				"type"		"list"
+				"1"		"1"
+				"1."		"Give"
+				"2"		"0"
+				"2."		"Take"
+			}
+		}
+
+
+
+	}
+	"ServerCommands"
+	{
+		"Extend Map"
+		{
+			"cmd"		"sm_extend #1"
+			"1"
+			{
+				"type"		"list"
+				"title"		"Extend for:"
+				"1"		"5"
+				"1."		"5 Minutes"
+				"2"		"10"
+				"2."		"10 Minutes"
+				"3"		"15"
+				"3."		"15 Minutes"
+				"4"		"20"
+				"4."		"20 Minutes"
+				"5"		"30"
+				"5."		"Half an Hour"
+				"6"		"45"
+				"6."		"45 Minutes"
+				"7"		"60"
+				"7."		"An Hour"
+			}
+		}
+
+	}
+	"Cvars"
+	{
+		"admin"		"sm_kick"
+		"Timelimit"
+		{
+			"cmd"			"mp_timelimit #1"
+			"execute"		"server"
+			"1"
+			{
+				"type" 		"list"
+				"title"		"Timelimit:"
+				"1"		"20"
+				"2"		"40"
+				"3"		"60"
+
+			}
+		}
+		"Friendly Fire"
+		{
+			"cmd"			"mp_friendlyfire #1"
+			"execute"		"server"
+			"1"
+			{
+				"type" 		"list"
+				"title"		"Friendly Fire:"
+				"1"		"1"
+				"1."		"On"
+				"2"		"0"
+				"2."		"Off"
+			}
+		}
+		"Show Damage Done"
+		{
+			"cmd"			"sm_showdamage #1"
+			"admin"			"sm_csay"
+			"execute"		"server"
+			"1"
+			{
+				"type" 		"list"
+				"title"		"Show Damage Done:"
+				"1"		"1"
+				"1."		"On"
+				"2"		"0"
+				"2."		"Off"
+			}
+		}
+	}
+	"Team management"
+	{
+		"Team Player"
+		{
+			"cmd"		"sm_team #1 #2"
+			"1"
+			{
+				"type" 		"player"
+			}
+			"2"
+			{
+				"type"		"list"
+				"title"		"Team:"
+				"1"		"1"
+				"1."		"Spectators"
+				"2"		"2"
+				"2."		"Terrorists"
+				"3"		"3"
+				"3."		"Counter-Terrorists"
+			}
+		}
+		"Switch Team"
+		{
+			"cmd"		"sm_teamswap"
+		}
+	}
+}
\ No newline at end of file
diff --git a/plugins/adminmenu.sp b/plugins/adminmenu.sp
index 9d21bc84..a7ce4bda 100644
--- a/plugins/adminmenu.sp
+++ b/plugins/adminmenu.sp
@@ -45,6 +45,8 @@ public Plugin:myinfo =
 	url = "http://www.sourcemod.net/"
 };
 
+new g_maxPlayers;
+
 /* Forwards */
 new Handle:hOnAdminMenuReady = INVALID_HANDLE;
 new Handle:hOnAdminMenuCreated = INVALID_HANDLE;
@@ -57,6 +59,8 @@ new TopMenuObject:obj_playercmds = INVALID_TOPMENUOBJECT;
 new TopMenuObject:obj_servercmds = INVALID_TOPMENUOBJECT;
 new TopMenuObject:obj_votingcmds = INVALID_TOPMENUOBJECT;
 
+#include "adminmenu/dynamicmenu.sp"
+
 public bool:AskPluginLoad(Handle:myself, bool:late, String:error[], err_max)
 {
 	CreateNative("GetAdminTopMenu", __GetAdminTopMenu);
@@ -81,7 +85,7 @@ public OnConfigsExecuted()
 	decl String:path[PLATFORM_MAX_PATH];
 	decl String:error[256];
 	
-	BuildPath(Path_SM, path, sizeof(path), "configs/adminmenu_sorting.txt");
+	BuildPath(Path_SM, path, sizeof(path), "configs/dynamicmenu/adminmenu_sorting.txt");
 	
 	if (!LoadTopMenuConfig(hAdminMenu, path, error, sizeof(error)))
 	{
@@ -90,27 +94,36 @@ public OnConfigsExecuted()
 	}
 }
 
+public OnMapStart()
+{
+	g_maxPlayers = GetMaxClients();
+	
+	ParseConfigs();
+}
+
 public OnAllPluginsLoaded()
 {
-	hAdminMenu = CreateTopMenu(CategoryHandler);
+	hAdminMenu = CreateTopMenu(DefaultCategoryHandler);
 	
 	obj_playercmds = AddToTopMenu(hAdminMenu, 
 		"PlayerCommands",
 		TopMenuObject_Category,
-		CategoryHandler,
+		DefaultCategoryHandler,
 		INVALID_TOPMENUOBJECT);
 
 	obj_servercmds = AddToTopMenu(hAdminMenu,
 		"ServerCommands",
 		TopMenuObject_Category,
-		CategoryHandler,
+		DefaultCategoryHandler,
 		INVALID_TOPMENUOBJECT);
 
 	obj_votingcmds = AddToTopMenu(hAdminMenu,
 		"VotingCommands",
 		TopMenuObject_Category,
-		CategoryHandler,
+		DefaultCategoryHandler,
 		INVALID_TOPMENUOBJECT);
+		
+	BuildDynamicMenu();
 	
 	Call_StartForward(hOnAdminMenuCreated);
 	Call_PushCell(hAdminMenu);
@@ -121,7 +134,7 @@ public OnAllPluginsLoaded()
 	Call_Finish();
 }
 
-public CategoryHandler(Handle:topmenu, 
+public DefaultCategoryHandler(Handle:topmenu, 
 						TopMenuAction:action,
 						TopMenuObject:object_id,
 						param,
diff --git a/plugins/adminmenu/dynamicmenu.sp b/plugins/adminmenu/dynamicmenu.sp
new file mode 100644
index 00000000..a8d9674e
--- /dev/null
+++ b/plugins/adminmenu/dynamicmenu.sp
@@ -0,0 +1,511 @@
+
+#define NAME_LENGTH 32
+#define CMD_LENGTH 255
+
+#define ARRAY_STRING_LENGTH 32
+
+new Handle:g_kvMenu;
+
+enum GroupCommands
+{
+	Handle:groupListName,
+	Handle:groupListCommand	
+};
+
+new g_groupList[GroupCommands];
+new g_groupCount;
+
+new Handle:g_configParser = INVALID_HANDLE;
+
+enum Places
+{
+	Place_Category,
+	Place_Item,
+	Place_ReplaceNum	
+};
+
+new String:g_command[MAXPLAYERS+1][CMD_LENGTH];
+new g_currentPlace[MAXPLAYERS+1][Places];
+
+/**
+ * What to put in the 'info' menu field (for PlayerList and Player_Team menus only)
+ */
+enum PlayerMethod
+{		
+	ClientId,				/** Client id number ( 1 - Maxplayers) */
+	UserId,					/** Client userid */
+	Name,					/** Client Name */
+	SteamId,				/** Client Steamid */
+	IpAddress,				/** Client's Ip Address */
+	UserId2					/** Userid (not prefixed with #) */
+};
+
+BuildDynamicMenu()
+{
+	if (g_kvMenu != INVALID_HANDLE)
+	{
+		CloseHandle(g_kvMenu);	
+	}
+	
+	g_kvMenu = CreateKeyValues("Commands");
+	new String:file[256];
+	BuildPath(Path_SM, file, 255, "configs/dynamicmenu/menu.ini");
+	FileToKeyValues(g_kvMenu, file);
+	
+	new String:name[NAME_LENGTH];
+	new String:buffer[NAME_LENGTH];
+	
+	
+	if (!KvGotoFirstSubKey(g_kvMenu))
+	{
+		return;
+	}
+	
+	decl String:admin[30];
+	
+	new TopMenuObject:categoryId;
+	
+	new catId;
+	new id;
+	
+	do
+	{		
+		KvGetSectionName(g_kvMenu, buffer, sizeof(buffer));
+
+		KvGetString(g_kvMenu, "admin", admin, sizeof(admin),"sm_admin");
+				
+		if ((categoryId =FindTopMenuCategory(hAdminMenu, buffer)) == INVALID_TOPMENUOBJECT)
+		{
+			categoryId = AddToTopMenu(hAdminMenu,
+							buffer,
+							TopMenuObject_Category,
+							DynamicMenuCategoryHandler,
+							INVALID_TOPMENUOBJECT,
+							admin,
+							ADMFLAG_GENERIC,
+							name);
+
+		}
+		
+		if (!KvGetSectionSymbol(g_kvMenu, catId))
+		{
+			LogError("Key Id not found for section: %s", buffer);
+			break;
+		}
+		
+		if (!KvGotoFirstSubKey(g_kvMenu))
+		{
+			return;
+		}
+		
+		do
+		{		
+			KvGetSectionName(g_kvMenu, buffer, sizeof(buffer));
+
+			KvGetString(g_kvMenu, "admin", admin, sizeof(admin),"");
+			
+			if (admin[0] == '\0')
+			{
+				//No 'admin' keyvalue was found
+				//Use the first argument of the 'cmd' string instead
+				
+				decl String:temp[64];
+				KvGetString(g_kvMenu, "cmd", temp, sizeof(temp),"");
+				
+				BreakString(temp, admin, sizeof(admin));
+			}
+							  
+			if (!KvGetSectionSymbol(g_kvMenu, id))
+			{
+				LogError("Key Id not found for section: %s");
+				break;
+			}
+			
+			decl String:keyId[64];
+			
+			Format(keyId, sizeof(keyId), "%i %i", catId, id);
+		
+			AddToTopMenu(hAdminMenu,
+							buffer,
+							TopMenuObject_Item,
+							DynamicMenuItemHandler,
+  							categoryId,
+  							admin,
+  							ADMFLAG_GENERIC,
+  							keyId);
+		
+		} while (KvGotoNextKey(g_kvMenu));
+		
+		KvGoBack(g_kvMenu);
+		
+	} while (KvGotoNextKey(g_kvMenu));
+	
+	KvRewind(g_kvMenu);	
+}
+
+ParseConfigs()
+{
+	if (g_configParser == INVALID_HANDLE)
+	{
+		g_configParser = SMC_CreateParser();
+	}
+	
+	SMC_SetReaders(g_configParser, NewSection, KeyValue, EndSection);
+	
+	if (g_groupList[groupListName] != INVALID_HANDLE)
+	{
+		CloseHandle(g_groupList[groupListName]);
+	}
+	
+	if (g_groupList[groupListCommand] != INVALID_HANDLE)
+	{
+		CloseHandle(g_groupList[groupListCommand]);
+	}
+	
+	g_groupList[groupListName] = CreateArray(ARRAY_STRING_LENGTH);
+	g_groupList[groupListCommand] = CreateArray(ARRAY_STRING_LENGTH);
+	
+	decl String:configPath[256];
+	BuildPath(Path_SM, configPath, sizeof(configPath), "configs/adminmenu_grouping.txt");
+	
+	if (!FileExists(configPath))
+	{
+		LogError("Unable to locate admin menu groups file, no groups loaded.");
+			
+		return;		
+	}
+	
+	new line;
+	new SMCError:err = SMC_ParseFile(g_configParser, configPath, line);
+	if (err != SMCError_Okay)
+	{
+		decl String:error[256];
+		SMC_GetErrorString(err, error, sizeof(error));
+		LogError("Could not parse file (line %d, file \"%s\"):", line, configPath);
+		LogError("Parser encountered error: %s", error);
+	}
+	
+	return;
+}
+
+public SMCResult:NewSection(Handle:smc, const String:name[], bool:opt_quotes)
+{
+
+}
+
+public SMCResult:KeyValue(Handle:smc, const String:key[], const String:value[], bool:key_quotes, bool:value_quotes)
+{
+	PushArrayString(g_groupList[groupListName], key);
+	PushArrayString(g_groupList[groupListCommand], value);
+}
+
+public SMCResult:EndSection(Handle:smc)
+{
+	g_groupCount = GetArraySize(g_groupList[groupListName]);
+}
+
+public DynamicMenuCategoryHandler(Handle:topmenu, 
+						TopMenuAction:action,
+						TopMenuObject:object_id,
+						param,
+						String:buffer[],
+						maxlength)
+{
+	if ((action == TopMenuAction_DisplayTitle) || (action == TopMenuAction_DisplayOption))
+	{
+		GetTopMenuObjName(topmenu, object_id, buffer, maxlength);
+	}
+}
+
+public DynamicMenuItemHandler(Handle:topmenu, 
+					  TopMenuAction:action,
+					  TopMenuObject:object_id,
+					  param,
+					  String:buffer[],
+					  maxlength)
+{
+	if (action == TopMenuAction_DisplayOption)
+	{
+		GetTopMenuObjName(topmenu, object_id, buffer, maxlength);
+	}
+	else if (action == TopMenuAction_SelectOption)
+	{	
+		new String:keyId[64];
+		new String:catId[64];
+		GetTopMenuInfoString(topmenu, object_id, keyId, sizeof(keyId));
+		
+		new start = BreakString(keyId, catId, sizeof(catId));
+		
+		new id = StringToInt(keyId[start]);
+		new category = StringToInt(catId);
+		
+		KvJumpToKeySymbol(g_kvMenu, category);
+		KvJumpToKeySymbol(g_kvMenu, id);
+		
+		KvGetString(g_kvMenu, "cmd", g_command[param], sizeof(g_command[]),"");
+		KvRewind(g_kvMenu);
+					
+		g_currentPlace[param][Place_Category] = category;
+		g_currentPlace[param][Place_Item] = id;
+		
+		ParamCheck(param);
+	}
+}
+
+public ParamCheck(client)
+{
+	new String:buffer[6];
+	new String:buffer2[6];
+
+	KvJumpToKeySymbol(g_kvMenu, g_currentPlace[client][Place_Category]);
+	KvJumpToKeySymbol(g_kvMenu, g_currentPlace[client][Place_Item]);
+	
+	new String:type[NAME_LENGTH];
+		
+	if (g_currentPlace[client][Place_ReplaceNum] < 1)
+	{
+		g_currentPlace[client][Place_ReplaceNum] = 1;
+	}
+	
+	Format(buffer, 5, "#%i", g_currentPlace[client][Place_ReplaceNum]);
+	Format(buffer2, 5, "@%i", g_currentPlace[client][Place_ReplaceNum]);
+	
+	if (StrContains(g_command[client], buffer) != -1 || StrContains(g_command[client], buffer2) != -1)
+	{
+		//user has a parameter to fill. lets do it.	
+		Format(buffer, 5, "%i", g_currentPlace[client][Place_ReplaceNum]);
+		KvJumpToKey(g_kvMenu, buffer); // Jump to current param
+		KvGetString(g_kvMenu, "type", type, sizeof(type),"list");
+		
+		new Handle:itemMenu = CreateMenu(Menu_Selection);
+		
+		new String:title[NAME_LENGTH];
+			
+		if (strncmp(type,"group",5)==0 && g_groupCount)
+		{	
+			decl String:nameBuffer[ARRAY_STRING_LENGTH];
+			decl String:commandBuffer[ARRAY_STRING_LENGTH];
+		
+			for (new i = 0; i<g_groupCount; i++)
+			{			
+				GetArrayString(g_groupList[groupListName], i, nameBuffer, sizeof(nameBuffer));
+				GetArrayString(g_groupList[groupListCommand], i, commandBuffer, sizeof(commandBuffer));
+				AddMenuItem(itemMenu, commandBuffer, nameBuffer);
+			}
+		}
+		else if (strncmp(type,"mapcycle",8) == 0)
+		{
+			decl String:path[200];
+			KvGetString(g_kvMenu, "path", path, sizeof(path),"mapcycle.txt");
+		
+			new Handle:file = OpenFile(path, "rt");
+			new String:readData[128];
+			
+			if(file != INVALID_HANDLE)
+			{
+				while(!IsEndOfFile(file) && ReadFileLine(file, readData, sizeof(readData)))
+				{
+					TrimString(readData);
+					
+					if (IsMapValid(readData))
+					{
+						AddMenuItem(itemMenu, readData, readData);
+					}
+				}
+			}
+		}
+		else if (StrContains(type, "player"))
+		{
+			new PlayerMethod:playermethod;
+			new String:method[NAME_LENGTH];
+			
+			KvGetString(g_kvMenu, "method", method, sizeof(method),"name");
+			
+			if (strncmp(method,"clientid",8)==0)
+			{
+				playermethod = ClientId;
+			}
+			else if (strncmp(method,"steamid",7)==0)
+			{
+				playermethod = SteamId;
+			}
+			else if (strncmp(method,"userid",6)==0)
+			{
+				playermethod = UserId;
+			}
+			else if (strncmp(method,"ip",2)==0)
+			{
+				playermethod = IpAddress;
+			}
+			else if (strncmp(method,"userid2",7)==0)
+			{
+				playermethod = UserId2;
+			}
+			else
+			{
+				playermethod = Name;
+			}
+	
+			
+			new String:nameBuffer[32];
+			new String:infoBuffer[32];
+			new String:temp[4];
+			
+			//loop through players. Add name as text and name/userid/steamid as info
+			for (new i=1; i<=g_maxPlayers; i++)
+			{
+				if (IsClientInGame(i))
+				{			
+					GetClientName(i, nameBuffer, 31);
+	
+					if (playermethod == UserId)
+					{
+						new userid = GetClientUserId(i);
+						Format(infoBuffer, sizeof(infoBuffer), "#%i", userid);
+						AddMenuItem(itemMenu, infoBuffer, nameBuffer);
+					}
+					if (playermethod == UserId2)
+					{
+						new userid = GetClientUserId(i);
+						Format(infoBuffer, sizeof(infoBuffer), "%i", userid);
+						AddMenuItem(itemMenu, infoBuffer, nameBuffer);
+					}
+					else if (playermethod == SteamId)
+					{
+						GetClientAuthString(i, infoBuffer, sizeof(infoBuffer));
+						AddMenuItem(itemMenu, infoBuffer, nameBuffer);
+					}
+					else if (playermethod == IpAddress)
+					{
+						GetClientIP(i, infoBuffer, sizeof(infoBuffer));
+						AddMenuItem(itemMenu, infoBuffer, nameBuffer);
+					}
+					else if (playermethod == Name)
+					{
+						AddMenuItem(itemMenu, nameBuffer, nameBuffer);
+					}
+					else //client id or none (so we'll give them the client id anyway)
+					{
+						Format(temp,3,"%i",i);
+						AddMenuItem(itemMenu, temp, nameBuffer);
+					}
+				}
+			}
+		}
+		else if (strncmp(type,"onoff",5) == 0)
+		{
+			AddMenuItem(itemMenu, "1", "On");
+			AddMenuItem(itemMenu, "0", "Off");
+		}		
+		else
+		{
+			//list menu
+
+			new String:temp[6];
+			new String:value[NAME_LENGTH];
+			new String:text[NAME_LENGTH];
+			new i=1;
+			new bool:more = true;
+					
+			new String:admin[NAME_LENGTH];
+						
+			do
+			{
+				// load the i and i. options from kv and make a menu from them (i* = required admin level to view)
+				Format(temp,3,"%i",i);
+				KvGetString(g_kvMenu, temp, value, sizeof(value), "");
+				
+				Format(temp,5,"%i.",i);
+				KvGetString(g_kvMenu, temp, text, sizeof(text), value);
+				
+				Format(temp,5,"%i*",i);
+				KvGetString(g_kvMenu, temp, admin, sizeof(admin),"");	
+				
+				if (value[0]=='\0')
+				{
+					more = false;
+				}
+				else if (CheckCommandAccess(client, admin, 0))
+				{
+					AddMenuItem(itemMenu, value, text);
+				}
+				
+				i++;
+								
+			} while (more);
+		
+		}
+		
+		KvGetString(g_kvMenu, "title", title, sizeof(title),"Choose an Option");
+		SetMenuTitle(itemMenu, title);
+		
+		DisplayMenu(itemMenu, client, MENU_TIME_FOREVER);
+	}
+	else
+	{	
+		//nothing else need to be done. Run teh command.
+		new String:execute[7];
+		KvGetString(g_kvMenu, "execute", execute, sizeof(execute), "player");
+		
+		DisplayTopMenu(hAdminMenu, client, TopMenuPosition_LastCategory);
+		
+		if (execute[0]=='p') // assume 'player' type execute option
+		{
+			FakeClientCommand(client, g_command[client]);
+		}
+		else // assume 'server' type execute option
+		{
+			InsertServerCommand(g_command[client]);
+			ServerExecute();
+		}
+
+		g_command[client][0] = '\0';
+		g_currentPlace[client][Place_ReplaceNum] = 1;
+	}
+	
+	KvRewind(g_kvMenu);
+}
+
+public Menu_Selection(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_End)
+	{
+		CloseHandle(menu);
+	}
+	
+	if (action == MenuAction_Select)
+	{
+		new String:info[NAME_LENGTH];
+ 
+		/* Get item info */
+		new bool:found = GetMenuItem(menu, param2, info, sizeof(info));
+		
+		if (!found)
+		{
+			return;
+		}
+		
+		new String:buffer[5];
+		new String:infobuffer[NAME_LENGTH+2];
+		Format(infobuffer, sizeof(infobuffer), "\"%s\"", info);
+		
+		Format(buffer, 4, "#%i", g_currentPlace[param1][Place_ReplaceNum]);
+		ReplaceString(g_command[param1], sizeof(g_command[]), buffer, infobuffer);
+		//replace #num with the selected option (quoted)
+		
+		Format(buffer, 4, "@%i", g_currentPlace[param1][Place_ReplaceNum]);
+		ReplaceString(g_command[param1], sizeof(g_command[]), buffer, info);
+		//replace @num with the selected option (unquoted)
+		
+		// Increment the parameter counter.
+		g_currentPlace[param1][Place_ReplaceNum]++;
+		
+		ParamCheck(param1);
+	}
+	
+	if (action == MenuAction_Cancel && param2 == MenuCancel_Exit)
+	{
+		//client exited we should go back to submenu i think
+		DisplayTopMenu(hAdminMenu, param1, TopMenuPosition_LastCategory);
+	}
+}
\ No newline at end of file