Creating Menus with the New Menu API (menu_create)

January 28, 2026 Daemon666 7 min read 209 преглеждания

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.

1. Create the menu

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
}

2. Add items and display

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.

3. Handle the selection

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.

4. Paging is automatic

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")

5. Access control and disabled items

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.

Common errors

  • Menus stop appearing after a while — you never called 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.
  • Wrong action runs — you compared 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.
  • Handler never called — the callback name passed to menu_create does not match a public function, or you displayed the menu to a disconnected/invalid id.
  • Colour codes printed literally — you escaped the backslash wrong. In Pawn a single \y is the code; a doubled \y prints the letters.
  • Menu closes instantly — you returned PLUGIN_CONTINUE from a register_clcmd that also matches another handler. Return PLUGIN_HANDLED.

Verification

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.

Сътрудници: Daemon666 ✦
Сподели: