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