5 #define ARRAY_STRING_LENGTH 32
10 Handle:groupListCommand
13 new g_groupList[GroupCommands];
16 new Handle:g_configParser = INVALID_HANDLE;
25 new String:g_command[MAXPLAYERS+1][CMD_LENGTH];
26 new g_currentPlace[MAXPLAYERS+1][Places];
29 * What to put in the 'info' menu field (for PlayerList and Player_Team menus only)
33 ClientId, /** Client id number ( 1 - Maxplayers) */
34 UserId, /** Client userid */
35 Name, /** Client Name */
36 SteamId, /** Client Steamid */
37 IpAddress, /** Client's Ip Address */
38 UserId2 /** Userid (not prefixed with #) */
60 ExecuteType:Item_execute,
66 SubMenu_Type:Submenu_type,
67 String:Submenu_title[32],
68 PlayerMethod:Submenu_method,
70 Handle:Submenu_listdata
73 new Handle:g_DataArray;
78 g_DataArray = CreateArray(sizeof(itemInput));
80 new String:executeBuffer[32];
83 kvMenu = CreateKeyValues("Commands");
84 KvSetEscapeSequences(kvMenu, true);
88 /* As a compatibility shim, we use the old file if it exists. */
89 BuildPath(Path_SM, file, 255, "configs/dynamicmenu/menu.ini");
92 LogError("Warning! configs/dynamicmenu/menu.ini is now configs/adminmenu_custom.txt.");
93 LogError("Read the 1.0.2 release notes, as the dynamicmenu folder has been removed.");
97 BuildPath(Path_SM, file, 255, "configs/adminmenu_custom.txt");
100 FileToKeyValues(kvMenu, file);
102 new String:name[NAME_LENGTH];
103 new String:buffer[NAME_LENGTH];
105 if (!KvGotoFirstSubKey(kvMenu))
110 decl String:admin[30];
112 new TopMenuObject:categoryId;
116 KvGetSectionName(kvMenu, buffer, sizeof(buffer));
118 KvGetString(kvMenu, "admin", admin, sizeof(admin),"sm_admin");
120 if ((categoryId =FindTopMenuCategory(hAdminMenu, buffer)) == INVALID_TOPMENUOBJECT)
122 categoryId = AddToTopMenu(hAdminMenu,
124 TopMenuObject_Category,
125 DynamicMenuCategoryHandler,
126 INVALID_TOPMENUOBJECT,
133 decl String:category_name[NAME_LENGTH];
134 strcopy(category_name, sizeof(category_name), buffer);
136 if (!KvGotoFirstSubKey(kvMenu))
143 KvGetSectionName(kvMenu, buffer, sizeof(buffer));
145 KvGetString(kvMenu, "admin", admin, sizeof(admin),"");
147 if (admin[0] == '\0')
149 //No 'admin' keyvalue was found
150 //Use the first argument of the 'cmd' string instead
152 decl String:temp[64];
153 KvGetString(kvMenu, "cmd", temp, sizeof(temp),"");
155 BreakString(temp, admin, sizeof(admin));
159 KvGetString(kvMenu, "cmd", itemInput[Item_cmd], sizeof(itemInput[Item_cmd]));
160 KvGetString(kvMenu, "execute", executeBuffer, sizeof(executeBuffer));
162 if (StrEqual(executeBuffer, "server"))
164 itemInput[Item_execute] = Execute_Server;
166 else //assume player type execute
168 itemInput[Item_execute] = Execute_Player;
171 /* iterate all submenus and load data into itemInput[Item_submenus] (adt array handle) */
174 decl String:countBuffer[10] = "1";
176 decl String:inputBuffer[48];
178 while (KvJumpToKey(kvMenu, countBuffer))
180 new submenuInput[Submenu];
184 itemInput[Item_submenus] = CreateArray(sizeof(submenuInput));
187 KvGetString(kvMenu, "type", inputBuffer, sizeof(inputBuffer));
189 if (strncmp(inputBuffer,"group",5)==0)
191 if (StrContains(inputBuffer, "player") != -1)
193 submenuInput[Submenu_type] = SubMenu_GroupPlayer;
197 submenuInput[Submenu_type] = SubMenu_Group;
200 else if (StrEqual(inputBuffer,"mapcycle"))
202 submenuInput[Submenu_type] = SubMenu_MapCycle;
204 KvGetString(kvMenu, "path", inputBuffer, sizeof(inputBuffer),"mapcycle.txt");
206 submenuInput[Submenu_listdata] = CreateDataPack();
207 WritePackString(submenuInput[Submenu_listdata], inputBuffer);
208 ResetPack(submenuInput[Submenu_listdata]);
210 else if (StrContains(inputBuffer, "player") != -1)
212 submenuInput[Submenu_type] = SubMenu_Player;
214 else if (StrEqual(inputBuffer,"onoff"))
216 submenuInput[Submenu_type] = SubMenu_OnOff;
218 else //assume 'list' type
220 submenuInput[Submenu_type] = SubMenu_List;
222 submenuInput[Submenu_listdata] = CreateDataPack();
225 new String:value[64];
227 new String:subadm[30]; // same as "admin", cf. line 110
229 new bool:more = true;
235 Format(temp,3,"%i",i);
236 KvGetString(kvMenu, temp, value, sizeof(value), "");
238 Format(temp,5,"%i.",i);
239 KvGetString(kvMenu, temp, text, sizeof(text), value);
241 Format(temp,5,"%i*",i);
242 KvGetString(kvMenu, temp, subadm, sizeof(subadm),"");
251 WritePackString(submenuInput[Submenu_listdata], value);
252 WritePackString(submenuInput[Submenu_listdata], text);
253 WritePackString(submenuInput[Submenu_listdata], subadm);
260 ResetPack(submenuInput[Submenu_listdata]);
261 submenuInput[Submenu_listcount] = listcount;
264 if ((submenuInput[Submenu_type] == SubMenu_Player) || (submenuInput[Submenu_type] == SubMenu_GroupPlayer))
266 KvGetString(kvMenu, "method", inputBuffer, sizeof(inputBuffer));
268 if (StrEqual(inputBuffer, "clientid"))
270 submenuInput[Submenu_method] = ClientId;
272 else if (StrEqual(inputBuffer, "steamid"))
274 submenuInput[Submenu_method] = SteamId;
276 else if (StrEqual(inputBuffer, "userid2"))
278 submenuInput[Submenu_method] = UserId2;
280 else if (StrEqual(inputBuffer, "userid"))
282 submenuInput[Submenu_method] = UserId;
284 else if (StrEqual(inputBuffer, "ip"))
286 submenuInput[Submenu_method] = IpAddress;
290 submenuInput[Submenu_method] = Name;
294 KvGetString(kvMenu, "title", inputBuffer, sizeof(inputBuffer));
295 strcopy(submenuInput[Submenu_title], sizeof(submenuInput[Submenu_title]), inputBuffer);
298 Format(countBuffer, sizeof(countBuffer), "%i", count);
300 PushArrayArray(itemInput[Item_submenus], submenuInput[0]);
305 /* Save this entire item into the global items array and add it to the menu */
307 new location = PushArrayArray(g_DataArray, itemInput[0]);
309 decl String:locString[10];
310 IntToString(location, locString, sizeof(locString));
312 if (AddToTopMenu(hAdminMenu,
315 DynamicMenuItemHandler,
319 locString) == INVALID_TOPMENUOBJECT)
321 LogError("Duplicate command name \"%s\" in adminmenu_custom.txt category \"%s\"", buffer, category_name);
324 } while (KvGotoNextKey(kvMenu));
328 } while (KvGotoNextKey(kvMenu));
335 if (g_configParser == INVALID_HANDLE)
337 g_configParser = SMC_CreateParser();
340 SMC_SetReaders(g_configParser, NewSection, KeyValue, EndSection);
342 if (g_groupList[groupListName] != INVALID_HANDLE)
344 CloseHandle(g_groupList[groupListName]);
347 if (g_groupList[groupListCommand] != INVALID_HANDLE)
349 CloseHandle(g_groupList[groupListCommand]);
352 g_groupList[groupListName] = CreateArray(ARRAY_STRING_LENGTH);
353 g_groupList[groupListCommand] = CreateArray(ARRAY_STRING_LENGTH);
355 decl String:configPath[256];
356 BuildPath(Path_SM, configPath, sizeof(configPath), "configs/dynamicmenu/adminmenu_grouping.txt");
357 if (FileExists(configPath))
359 LogError("Warning! configs/dynamicmenu/adminmenu_grouping.txt is now configs/adminmenu_grouping.txt.");
360 LogError("Read the 1.0.2 release notes, as the dynamicmenu folder has been removed.");
364 BuildPath(Path_SM, configPath, sizeof(configPath), "configs/adminmenu_grouping.txt");
367 if (!FileExists(configPath))
369 LogError("Unable to locate admin menu groups file: %s", configPath);
375 new SMCError:err = SMC_ParseFile(g_configParser, configPath, line);
376 if (err != SMCError_Okay)
378 decl String:error[256];
379 SMC_GetErrorString(err, error, sizeof(error));
380 LogError("Could not parse file (line %d, file \"%s\"):", line, configPath);
381 LogError("Parser encountered error: %s", error);
387 public SMCResult:NewSection(Handle:smc, const String:name[], bool:opt_quotes)
392 public SMCResult:KeyValue(Handle:smc, const String:key[], const String:value[], bool:key_quotes, bool:value_quotes)
394 PushArrayString(g_groupList[groupListName], key);
395 PushArrayString(g_groupList[groupListCommand], value);
398 public SMCResult:EndSection(Handle:smc)
400 g_groupCount = GetArraySize(g_groupList[groupListName]);
403 public DynamicMenuCategoryHandler(Handle:topmenu,
404 TopMenuAction:action,
405 TopMenuObject:object_id,
410 if ((action == TopMenuAction_DisplayTitle) || (action == TopMenuAction_DisplayOption))
412 GetTopMenuObjName(topmenu, object_id, buffer, maxlength);
416 public DynamicMenuItemHandler(Handle:topmenu,
417 TopMenuAction:action,
418 TopMenuObject:object_id,
423 if (action == TopMenuAction_DisplayOption)
425 GetTopMenuObjName(topmenu, object_id, buffer, maxlength);
427 else if (action == TopMenuAction_SelectOption)
429 new String:locString[10];
430 GetTopMenuInfoString(topmenu, object_id, locString, sizeof(locString));
432 new location = StringToInt(locString);
435 GetArrayArray(g_DataArray, location, output[0]);
437 strcopy(g_command[param], sizeof(g_command[]), output[Item_cmd]);
439 g_currentPlace[param][Place_Item] = location;
440 g_currentPlace[param][Place_ReplaceNum] = 1;
446 public ParamCheck(client)
448 new String:buffer[6];
449 new String:buffer2[6];
451 new outputItem[Item];
452 new outputSubmenu[Submenu];
454 GetArrayArray(g_DataArray, g_currentPlace[client][Place_Item], outputItem[0]);
456 if (g_currentPlace[client][Place_ReplaceNum] < 1)
458 g_currentPlace[client][Place_ReplaceNum] = 1;
461 Format(buffer, 5, "#%i", g_currentPlace[client][Place_ReplaceNum]);
462 Format(buffer2, 5, "@%i", g_currentPlace[client][Place_ReplaceNum]);
464 if (StrContains(g_command[client], buffer) != -1 || StrContains(g_command[client], buffer2) != -1)
466 GetArrayArray(outputItem[Item_submenus], g_currentPlace[client][Place_ReplaceNum] - 1, outputSubmenu[0]);
468 new Handle:itemMenu = CreateMenu(Menu_Selection);
469 SetMenuExitBackButton(itemMenu, true);
471 if ((outputSubmenu[Submenu_type] == SubMenu_Group) || (outputSubmenu[Submenu_type] == SubMenu_GroupPlayer))
473 decl String:nameBuffer[ARRAY_STRING_LENGTH];
474 decl String:commandBuffer[ARRAY_STRING_LENGTH];
476 for (new i = 0; i<g_groupCount; i++)
478 GetArrayString(g_groupList[groupListName], i, nameBuffer, sizeof(nameBuffer));
479 GetArrayString(g_groupList[groupListCommand], i, commandBuffer, sizeof(commandBuffer));
480 AddMenuItem(itemMenu, commandBuffer, nameBuffer);
484 if (outputSubmenu[Submenu_type] == SubMenu_MapCycle)
486 decl String:path[200];
487 ReadPackString(outputSubmenu[Submenu_listdata], path, sizeof(path));
488 ResetPack(outputSubmenu[Submenu_listdata]);
490 new Handle:file = OpenFile(path, "rt");
491 new String:readData[128];
493 if(file != INVALID_HANDLE)
495 while(!IsEndOfFile(file) && ReadFileLine(file, readData, sizeof(readData)))
497 TrimString(readData);
499 if (IsMapValid(readData))
501 AddMenuItem(itemMenu, readData, readData);
506 else if ((outputSubmenu[Submenu_type] == SubMenu_Player) || (outputSubmenu[Submenu_type] == SubMenu_GroupPlayer))
508 new PlayerMethod:playermethod = outputSubmenu[Submenu_method];
510 new String:nameBuffer[32];
511 new String:infoBuffer[32];
514 //loop through players. Add name as text and name/userid/steamid as info
515 for (new i=1; i<=MaxClients; i++)
517 if (IsClientInGame(i))
519 GetClientName(i, nameBuffer, 31);
521 switch (playermethod)
525 new userid = GetClientUserId(i);
526 Format(infoBuffer, sizeof(infoBuffer), "#%i", userid);
527 AddMenuItem(itemMenu, infoBuffer, nameBuffer);
531 new userid = GetClientUserId(i);
532 Format(infoBuffer, sizeof(infoBuffer), "%i", userid);
533 AddMenuItem(itemMenu, infoBuffer, nameBuffer);
537 GetClientAuthString(i, infoBuffer, sizeof(infoBuffer));
538 AddMenuItem(itemMenu, infoBuffer, nameBuffer);
542 GetClientIP(i, infoBuffer, sizeof(infoBuffer));
543 AddMenuItem(itemMenu, infoBuffer, nameBuffer);
547 AddMenuItem(itemMenu, nameBuffer, nameBuffer);
549 default: //assume client id
551 Format(temp,3,"%i",i);
552 AddMenuItem(itemMenu, temp, nameBuffer);
558 else if (outputSubmenu[Submenu_type] == SubMenu_OnOff)
560 AddMenuItem(itemMenu, "1", "On");
561 AddMenuItem(itemMenu, "0", "Off");
565 new String:value[64];
568 new String:admin[NAME_LENGTH];
570 for (new i=0; i<outputSubmenu[Submenu_listcount]; i++)
572 ReadPackString(outputSubmenu[Submenu_listdata], value, sizeof(value));
573 ReadPackString(outputSubmenu[Submenu_listdata], text, sizeof(text));
574 ReadPackString(outputSubmenu[Submenu_listdata], admin, sizeof(admin));
576 if (CheckCommandAccess(client, admin, 0))
578 AddMenuItem(itemMenu, value, text);
582 ResetPack(outputSubmenu[Submenu_listdata]);
585 SetMenuTitle(itemMenu, outputSubmenu[Submenu_title]);
587 DisplayMenu(itemMenu, client, MENU_TIME_FOREVER);
591 //nothing else need to be done. Run teh command.
593 DisplayTopMenu(hAdminMenu, client, TopMenuPosition_LastCategory);
595 decl String:unquotedCommand[CMD_LENGTH];
596 UnQuoteString(g_command[client], unquotedCommand, sizeof(unquotedCommand), "#@");
598 if (outputItem[Item_execute] == Execute_Player) // assume 'player' type execute option
600 FakeClientCommand(client, unquotedCommand);
602 else // assume 'server' type execute option
604 InsertServerCommand(unquotedCommand);
608 g_command[client][0] = '\0';
609 g_currentPlace[client][Place_ReplaceNum] = 1;
613 public Menu_Selection(Handle:menu, MenuAction:action, param1, param2)
615 if (action == MenuAction_End)
620 if (action == MenuAction_Select)
622 new String:unquotedinfo[NAME_LENGTH];
625 new bool:found = GetMenuItem(menu, param2, unquotedinfo, sizeof(unquotedinfo));
632 new String:info[NAME_LENGTH*2+1];
633 QuoteString(unquotedinfo, info, sizeof(info), "#@");
636 new String:buffer[6];
637 new String:infobuffer[NAME_LENGTH+2];
638 Format(infobuffer, sizeof(infobuffer), "\"%s\"", info);
640 Format(buffer, 5, "#%i", g_currentPlace[param1][Place_ReplaceNum]);
641 ReplaceString(g_command[param1], sizeof(g_command[]), buffer, infobuffer);
642 //replace #num with the selected option (quoted)
644 Format(buffer, 5, "@%i", g_currentPlace[param1][Place_ReplaceNum]);
645 ReplaceString(g_command[param1], sizeof(g_command[]), buffer, info);
646 //replace @num with the selected option (unquoted)
648 // Increment the parameter counter.
649 g_currentPlace[param1][Place_ReplaceNum]++;
654 if (action == MenuAction_Cancel && param2 == MenuCancel_ExitBack)
656 //client exited we should go back to submenu i think
657 DisplayTopMenu(hAdminMenu, param1, TopMenuPosition_LastCategory);
662 stock bool:QuoteString(String:input[], String:output[], maxlen, String:quotechars[])
665 new len = strlen(input);
667 for (new i=0; i<len; i++)
669 output[count] = input[i];
674 /* Null terminate for safety */
675 output[maxlen-1] = 0;
679 if (FindCharInString(quotechars, input[i]) != -1 || input[i] == '\\')
681 /* This char needs escaping */
682 output[count] = '\\';
687 /* Null terminate for safety */
688 output[maxlen-1] = 0;
699 stock bool:UnQuoteString(String:input[], String:output[], maxlen, String:quotechars[])
702 new len = strlen(input);
704 output[0] = input[0];
706 for (new i=1; i<len; i++)
708 output[count] = input[i];
711 if (input[i+1] == '\\' && (input[i] == '\\' || FindCharInString(quotechars, input[i]) != -1))
713 /* valid quotechar followed by a backslash - Skip */
719 /* Null terminate for safety */
720 output[maxlen-1] = 0;