diff --git a/amxmodx/CMisc.cpp b/amxmodx/CMisc.cpp index 3cf9957f..e1990618 100755 --- a/amxmodx/CMisc.cpp +++ b/amxmodx/CMisc.cpp @@ -65,20 +65,8 @@ void CPlayer::Disconnect() authorized = false; teamIdsInitialized = false; - if (newmenu != -1) - { - Menu *pMenu = g_NewMenus[newmenu]; - if (pMenu) - { - //prevent recursion - newmenu = -1; - menu = 0; - executeForwards(pMenu->func, - static_cast(ENTINDEX(pEdict)), - static_cast(pMenu->thisId), - static_cast(MENU_EXIT)); - } - } + if (Menu *pMenu = get_menu_by_id(newmenu)) + pMenu->Close(index); List::iterator iter, end=queries.end(); for (iter=queries.begin(); iter!=end; iter++) diff --git a/amxmodx/amxmodx.cpp b/amxmodx/amxmodx.cpp index 8d0c644d..d491be17 100755 --- a/amxmodx/amxmodx.cpp +++ b/amxmodx/amxmodx.cpp @@ -32,6 +32,7 @@ #include #include "amxmodx.h" #include "CMenu.h" +#include "newmenus.h" #include "natives.h" #include "debugger.h" #include "binlog.h" @@ -1292,6 +1293,10 @@ static cell AMX_NATIVE_CALL show_menu(AMX *amx, cell *params) /* 3 param */ pPlayer->keys = 0; pPlayer->menu = 0; + // Fire newmenu callback so closing it can be handled by the plugin + if (Menu *pMenu = get_menu_by_id(pPlayer->newmenu)) + pMenu->Close(pPlayer->index); + UTIL_FakeClientCommand(pPlayer->pEdict, "menuselect", "10", 0); pPlayer->keys = keys; @@ -1303,7 +1308,6 @@ static cell AMX_NATIVE_CALL show_menu(AMX *amx, cell *params) /* 3 param */ else pPlayer->menuexpire = gpGlobals->time + static_cast(time); - pPlayer->newmenu = -1; pPlayer->page = 0; UTIL_ShowMenu(pPlayer->pEdict, keys, time, sMenu, ilen); } @@ -1324,6 +1328,10 @@ static cell AMX_NATIVE_CALL show_menu(AMX *amx, cell *params) /* 3 param */ pPlayer->keys = 0; pPlayer->menu = 0; + // Fire newmenu callback so closing it can be handled by the plugin + if (Menu *pMenu = get_menu_by_id(pPlayer->newmenu)) + pMenu->Close(pPlayer->index); + UTIL_FakeClientCommand(pPlayer->pEdict, "menuselect", "10", 0); pPlayer->keys = keys; @@ -1335,7 +1343,6 @@ static cell AMX_NATIVE_CALL show_menu(AMX *amx, cell *params) /* 3 param */ else pPlayer->menuexpire = gpGlobals->time + static_cast(time); - pPlayer->newmenu = -1; pPlayer->page = 0; UTIL_ShowMenu(pPlayer->pEdict, keys, time, sMenu, ilen); } @@ -2947,7 +2954,11 @@ static cell AMX_NATIVE_CALL get_user_menu(AMX *amx, cell *params) /* 3 param */ { if (gpGlobals->time > pPlayer->menuexpire) { - pPlayer->menu = 0; + if (Menu *pMenu = get_menu_by_id(pPlayer->newmenu)) + pMenu->Close(pPlayer->index); + else + pPlayer->menu = 0; + *cpMenu = 0; *cpKeys = 0; diff --git a/amxmodx/meta_api.cpp b/amxmodx/meta_api.cpp index f5fd25f5..67172920 100755 --- a/amxmodx/meta_api.cpp +++ b/amxmodx/meta_api.cpp @@ -961,12 +961,21 @@ void C_ClientCommand(edict_t *pEntity) if (pPlayer->keys & bit_key) { - if ((pPlayer->menu > 0 && !pPlayer->vgui) && (gpGlobals->time > pPlayer->menuexpire)) + if (gpGlobals->time > pPlayer->menuexpire) { - pPlayer->menu = 0; - pPlayer->keys = 0; + if (Menu *pMenu = get_menu_by_id(pPlayer->newmenu)) + { + pMenu->Close(pPlayer->index); - RETURN_META(MRES_SUPERCEDE); + RETURN_META(MRES_SUPERCEDE); + } + else if (pPlayer->menu > 0 && !pPlayer->vgui) + { + pPlayer->menu = 0; + pPlayer->keys = 0; + + RETURN_META(MRES_SUPERCEDE); + } } int menuid = pPlayer->menu; @@ -978,10 +987,8 @@ void C_ClientCommand(edict_t *pEntity) { int menu = pPlayer->newmenu; pPlayer->newmenu = -1; - - if (menu >= 0 && menu < (int)g_NewMenus.size() && g_NewMenus[menu]) + if (Menu *pMenu = get_menu_by_id(menu)) { - Menu *pMenu = g_NewMenus[menu]; int item = pMenu->PagekeyToItem(pPlayer->page, pressed_key+1); if (item == MENU_BACK) { diff --git a/amxmodx/newmenus.cpp b/amxmodx/newmenus.cpp index 0cbba984..209fca98 100755 --- a/amxmodx/newmenus.cpp +++ b/amxmodx/newmenus.cpp @@ -79,6 +79,14 @@ void validate_menu_text(char *str) *(str-offs) = '\0'; } } +} + +Menu *get_menu_by_id(int id) +{ + if (id < 0 || size_t(id) >= g_NewMenus.size() || !g_NewMenus[id]) + return NULL; + + return g_NewMenus[id]; } Menu::Menu(const char *title, AMX *amx, int fid) : m_Title(title), m_ItemColor("\\r"), @@ -321,6 +329,26 @@ bool Menu::Display(int player, page_t page) return true; } +void Menu::Close(int player) +{ + CPlayer *pPlayer = GET_PLAYER_POINTER_I(player); + + int status; + if (gpGlobals->time > pPlayer->menuexpire) + status = MENU_TIMEOUT; + else + status = MENU_EXIT; + + pPlayer->keys = 0; + pPlayer->menu = 0; + pPlayer->newmenu = -1; + + executeForwards(func, + static_cast(player), + static_cast(thisId), + static_cast(status)); +} + const char *Menu::GetTextString(int player, page_t page, int &keys) { page_t pages = GetPageCount(); @@ -590,10 +618,10 @@ const char *Menu::GetTextString(int player, page_t page, int &keys) return m_Text.c_str(); } -#define GETMENU(p) if (p >= (int)g_NewMenus.size() || p < 0 || !g_NewMenus[p] || g_NewMenus[p]->isDestroying) { \ +#define GETMENU(p) Menu *pMenu = get_menu_by_id(p); \ + if (pMenu == NULL || pMenu->isDestroying) { \ LogError(amx, AMX_ERR_NATIVE, "Invalid menu id %d(%d)", p, g_NewMenus.size()); \ - return 0; } \ - Menu *pMenu = g_NewMenus[p]; + return 0; } //Makes a new menu handle (-1 for failure) //native csdm_makemenu(title[]); @@ -798,14 +826,8 @@ static cell AMX_NATIVE_CALL menu_display(AMX *amx, cell *params) break; } - Menu *pOther = g_NewMenus[menu]; - - pPlayer->newmenu = -1; - pPlayer->menu = 0; - executeForwards(pOther->func, - static_cast(player), - static_cast(pOther->thisId), - static_cast(MENU_EXIT)); + Menu *pOther = g_NewMenus[menu]; + pOther->Close(pPlayer->index); /* Infinite loop counter */ if (++loops >= 10) @@ -815,8 +837,14 @@ static cell AMX_NATIVE_CALL menu_display(AMX *amx, cell *params) } } - // This will set the expire time of the menu to infinite - pPlayer->menuexpire = INFINITE; + int time = -1; + if (params[0] / sizeof(cell) >= 4) + time = params[4]; + + if (time < 0) + pPlayer->menuexpire = INFINITE; + else + pPlayer->menuexpire = gpGlobals->time + static_cast(time); return pMenu->Display(player, page); } @@ -1029,10 +1057,10 @@ static cell AMX_NATIVE_CALL menu_setprop(AMX *amx, cell *params) return 1; } -#define GETMENU_R(p) if (p >= (int)g_NewMenus.size() || p < 0 || !g_NewMenus[p]) { \ +#define GETMENU_R(p) Menu *pMenu = get_menu_by_id(p); \ + if (pMenu == NULL) { \ LogError(amx, AMX_ERR_NATIVE, "Invalid menu id %d(%d)", p, g_NewMenus.size()); \ - return 0; } \ - Menu *pMenu = g_NewMenus[p]; + return 0; } static cell AMX_NATIVE_CALL menu_cancel(AMX *amx, cell *params) { @@ -1047,24 +1075,16 @@ static cell AMX_NATIVE_CALL menu_cancel(AMX *amx, cell *params) CPlayer *player = GET_PLAYER_POINTER_I(index); if (!player->ingame) { - LogError(amx, AMX_ERR_NATIVE, "Played %d is not in game", index); + LogError(amx, AMX_ERR_NATIVE, "Player %d is not in game", index); return 0; } - int menu = player->newmenu; - if (menu < 0 || menu >= (int)g_NewMenus.size() || !g_NewMenus[menu]) - return 0; + if (Menu *pMenu = get_menu_by_id(player->newmenu)) { + pMenu->Close(player->index); + return 1; + } - Menu *pMenu = g_NewMenus[menu]; - - player->newmenu = -1; - player->menu = 0; - executeForwards(pMenu->func, - static_cast(index), - static_cast(pMenu->thisId), - static_cast(MENU_EXIT)); - - return 1; + return 0; } static cell AMX_NATIVE_CALL menu_destroy(AMX *amx, cell *params) @@ -1083,13 +1103,8 @@ static cell AMX_NATIVE_CALL menu_destroy(AMX *amx, cell *params) { player = GET_PLAYER_POINTER_I(i); if (player->newmenu == pMenu->thisId) - { - player->newmenu = -1; - player->menu = 0; - executeForwards(pMenu->func, - static_cast(i), - static_cast(pMenu->thisId), - static_cast(MENU_EXIT)); + { + pMenu->Close(player->index); } } g_NewMenus[params[1]] = NULL; diff --git a/amxmodx/newmenus.h b/amxmodx/newmenus.h index 558bd770..94d79af0 100755 --- a/amxmodx/newmenus.h +++ b/amxmodx/newmenus.h @@ -32,6 +32,7 @@ #ifndef _INCLUDE_NEWMENUS_H #define _INCLUDE_NEWMENUS_H +#define MENU_TIMEOUT -4 #define MENU_EXIT -3 #define MENU_BACK -2 #define MENU_MORE -1 @@ -126,7 +127,8 @@ public: const char *GetTextString(int player, page_t page, int &keys); bool Display(int player, page_t page); - + void Close(int player); + int PagekeyToItem(page_t page, item_t key); int GetMenuMenuid(); public: @@ -150,6 +152,7 @@ public: }; void ClearMenus(); +Menu *get_menu_by_id(int id); extern CVector g_NewMenus; extern AMX_NATIVE_INFO g_NewMenuNatives[]; diff --git a/plugins/include/amxconst.inc b/plugins/include/amxconst.inc index 1f902d34..2c0a298c 100755 --- a/plugins/include/amxconst.inc +++ b/plugins/include/amxconst.inc @@ -269,9 +269,10 @@ enum { #define INVALID_PLUGIN_ID -1 -#define MENU_EXIT -3 -#define MENU_BACK -2 -#define MENU_MORE -1 +#define MENU_TIMEOUT -4 +#define MENU_EXIT -3 +#define MENU_BACK -2 +#define MENU_MORE -1 #define ITEM_IGNORE 0 #define ITEM_ENABLED 1 #define ITEM_DISABLED 2 diff --git a/plugins/include/newmenus.inc b/plugins/include/newmenus.inc index 3ef69f4d..b9345b41 100644 --- a/plugins/include/newmenus.inc +++ b/plugins/include/newmenus.inc @@ -115,13 +115,21 @@ native menu_items(menu); * when the item is less than 0 (i.e. calling this from a cancelled menu will * result in an error). * + * Starting with 1.8.3 this allows to specify a menu timeout similar to the + * show_menu native. If the menu exists on the client past the timeout *any* + * further action will send the MENU_TIMEOUT status code to the menu handler. + * That includes actions which would otherwise send MENU_EXIT, such as the + * client selecting an item or disconnecting and calling menu_cancel or + * menu_destroy on a live menu. + * * @param id Client index. * @param menu Menu resource identifier. * @param page Page to start from (starting from 0). + * @param time If >=0 menu will timeout after this many seconds * @noreturn * @error Invalid menu resource or client index. */ -native menu_display(id, menu, page=0); +native menu_display(id, menu, page=0, time=-1); /** * Given a page on a menu and a keypress on that page, returns the item id selected.