--- title: "Creating Menus with the New Menu API (menu_create)" excerpt: "Build interactive menus with menu_create, menu_additem and menu_display, handle selections and paging, and destroy menus so they do not leak." category: "plugin-dev" tags: "menus, amxmodx" image: "" read_time: "7 min read" ---
AMX Mod X has two menu systems. The old one (show_menu with a keys bitmask and register_menucmd) still compiles, but it is fiddly and caps at ten items with manual paging. The new menu API — menu_create, menu_additem, menu_display — handles paging, back/next/exit, and access control for you. It is what every modern plugin uses. This guide builds a working menu end to end and covers the one thing people forget: destroying it.
menu_create(title, handler) returns a menu id and registers the callback that receives selections. Build the menu when you are about to show it, not once at plugin load, because the item list is usually dynamic:
#include <amxmodx>
public plugin_init()
{
register_plugin("Menu Demo", "1.0", "CSB")
register_clcmd("say /tools", "cmd_tools")
}
public cmd_tools(id)
{
show_tools_menu(id)
return PLUGIN_HANDLED
}
menu_additem(menu, text, info) adds a selectable line. The info string is an opaque payload handed back to your handler when that item is picked — use it to encode what the item means:
show_tools_menu(id)
{
new menu = menu_create("\yCSB Tools\w", "tools_handler")
menu_additem(menu, "Heal to 100", "heal")
menu_additem(menu, "Give armor", "armor")
menu_additem(menu, "Teleport to spawn", "tp")
menu_display(id, menu, 0) // 0 = first page
}
Colour codes work in item text: \y yellow, \w white,
red, \d dim (used automatically for disabled items). menu_display's third argument is the page number.
The handler receives the player, the menu, and the chosen item index. Two special values matter: MENU_EXIT when the player closes the menu, and the item index otherwise. Read the item's info string with menu_item_getinfo, act on it, then destroy the menu:
public tools_handler(id, menu, item)
{
if (item == MENU_EXIT)
{
menu_destroy(menu)
return PLUGIN_HANDLED
}
new info[16], name[64], access, callback
menu_item_getinfo(menu, item, access, info, charsmax(info),
name, charsmax(name), callback)
if (equal(info, "heal"))
set_user_health(id, 100)
else if (equal(info, "armor"))
set_user_armor(id, 100)
else if (equal(info, "tp"))
// teleport logic here
client_print(id, print_chat, "[CSB] Teleported.")
menu_destroy(menu)
return PLUGIN_HANDLED
}
Returning PLUGIN_HANDLED tells AMXX you consumed the selection. If you want the menu to stay open after a pick, re-display it instead of destroying, but for most action menus one selection is the end.
Add more than seven items and the new API inserts Next and Back entries and pages them for you — no bitmask arithmetic. Slot 8 becomes Next, slot 9 Back, slot 0 Exit by default. You can change the reserved slots and labels with menu_setprop:
menu_setprop(menu, MPROP_EXITNAME, "Close") menu_setprop(menu, MPROP_BACKNAME, "Previous") menu_setprop(menu, MPROP_NEXTNAME, "More")
The fourth argument to menu_additem is an access flag — the item is greyed out and unselectable for players without it. Combine with get_user_flags to build an admin menu whose entries adapt to the viewer:
menu_additem(menu, "Ban player", "ban", ADMIN_BAN) menu_additem(menu, "Slay player", "slay", ADMIN_SLAY)
A player lacking ADMIN_BAN sees "Ban player" dimmed and cannot pick it, without any check in your handler.
menu_destroy. Every menu_create allocates; leaking them exhausts the menu pool and new menus silently fail. Destroy in the handler on both MENU_EXIT and every real selection.item (a page-relative index) instead of the info string. With paging, item 0 on page 2 is not your first item. Always branch on the info string from menu_item_getinfo.menu_create does not match a public function, or you displayed the menu to a disconnected/invalid id.\y is the code; a doubled \y prints the letters.PLUGIN_CONTINUE from a register_clcmd that also matches another handler. Return PLUGIN_HANDLED.Bind the open command, type it in chat, and confirm the menu shows with correct colours and your items. Pick each item and confirm the right action runs. Add ten items and confirm Next/Back appear and page correctly. Finally, open and close the menu a few dozen times and confirm it still opens — that is the leak test for missing menu_destroy calls. To learn the language fundamentals behind this, see Pawn basics for AMXX; for a real admin menu built on this API, look at CSB Admin Menu.