[ Новые сообщения · Участники · Правила форума · Поиск · RSS ]
  • Страница 1 из 1
  • 1
Форум » Форум » Уроки SourceMod (SourcePawn) Скриптинга » Создание меню в SourcePawn (http://forum.sn-project.ru/viewtopic.php?f=75&t=2045)
Создание меню в SourcePawn
rootДата: Воскресенье, 03.02.2013, 10:26 | Сообщение # 1
Генералиссимус
Группа: Администраторы
Сообщений: 561
Статус: Offline
Создание меню в SourcePawn

SourceMod имеет обширный API для создания и отображения меню клиентам.

Стили
Объект верхнего уровня MenuStyle (IMenuStyle в C++). Есть два стиля отображения меню
  • Стиль Valve - так называемое "ESC" меню; 8 элементов на странице
  • Стиль Radio - так называемое "AMX" меню; 10 элементов на странице
Каждый MenuStyle имеет свои собственные правила и свойства. Два разных меню могут существовать на экране игрока как Valve меню и Radio меню. В то же время, SourceMod будет в состоянии управлять этими меню. Это связано с тем, что каждый стиль отслеживает свое меню отдельно.

Панели
Объект с более низким уровня интерфейсом Panels (IMenuPanel в C++). Панели позволяют сделать отображение, используя лишь только текст т.е. не используя выделительных пунктов (Select). 
Панели отображаются временно. Хотя они могут быть сохранены на неопределенный срок, не рекомендуется это делать.
Стиль Valve
  • Максимальное количество элементов на странице 8
  • Заблокированные элементы не могут быть осуществлены
  • Raw текст не может быть осуществлен
  • Осуществление между текстом пространства не добавят возможности добавить в панель больше символов
  • Клиент должен будет нажать кнопку "ESC" или, по крайней открыть консоль для просмотра меню
Стиль Radio
  • Максимальное количество элементов на странице 10
  • Оглавление белое, элементы желтые, но если их отключить, то они будут белыми
  • Элемент '0' всегда белый. Это означает, что навигационные кнопки управления всегда белого цвета

Меню
Есть простые Menu (IBaseMenu в C++). Эти вспомогательные объекты, предназначенные для хранения меню на основе выбора элементов. В отличие от низкого уровня панелей, меню могут содержать множество элементов, а также могут содержать только те пункты, которые выбираются (т. е. не содержат "белого" текста). 
Они делятся на две категории:
Не пронумерованные - меню содержит в себе только лишь определенное количество элементов. 
Нет пунктов навигации (Вперед; Назад). Исключение: Выход.
  • Назад (Previous) - Используется для возвращения просмотренных элементов; Перелистываемые страницы назад
    • Стиль Valve: Позиция в меню: 6
    • Стиль Radio: Позиция в меню: 8
  • Далее (Next) - Используется для просматривания следующих страниц; Перелистывание страницы вперед
    • Стиль Valve: Позиция в меню: 7
    • Стиль Radio: Позиция в меню: 9
  • Выход (Exit) - Используется для выхода из меню
    • Стиль Valve: Позиция в меню: 8
    • Стиль Radio: Позиция в меню: 10


Цель меню - Упростить процедуру хранения и отображения информации. Таким образом, меню не позволяют добавить raw текст, так как это значительно усложняет отображение алгоритма. 
Примечание. C++ API поддерживает подключение IBaseMenu процедуры отображения и добавления raw текста, это будет добавлено в сценарии API в ближайшее время.
Внутри меню отображение используется с помощью RenderMenu алгоритма. Этот алгоритм создает временную панель и наполняет ее элементы из меню. Эта панель будет отображаться на клиенте. Алгоритм пытается создать свободное перемещение между всеми меню, и во всех стилях. Таким образом, любое меню отображается с помощью IBaseMenu класса, или меню Handle будет отображаться и использоваться так же как и меню Panel API.

Обзор
Меню являются системой обратного вызова. Каждый обратный вызов представляет собой действие, которое происходит во время всего цикла действия меню. Цикл состоит из некоторых уведомлений:
  • Начало действия уведомлений
    • Отображение уведомления клиенту
    • Выбор пункта в меню
  • Конец действия уведомлений

Спецификация
Для C++, IBaseMenu всегда доступен. Для SourcePawn, Menu Handle и MenuAction всегда устанавливаются в MenuHandler обратного вызова. В отличие от C++, API позволяет SourcePawn выполнять определенные действия, если только меню было запрошено во время создания. Это оптимизация. Тем не менее, некоторые действия не могут быть предотвращены создания.
    Start. Создание меню, причем OnMenuEnd гарантированно будет вызываться.
    • MenuAction_Start() в SourcePawn. Это действие не срабатывает при вызове.
      • param1: Игнорирование. Всегда 0
      • param2: Игнорирование. Всегда 0
    Display. Отображение меню клиенту.
    • MenuAction_Display в SourcePawn. Это действие не срабатывает при вызове.
      • param1: Индекс клиента, которому показано меню
      • param2: Handle в меню
    Select. Выбор пункта меню.
    • MenuAction_Select в SourcePawn. Это действие срабатывает, не смотря на вызов.
      • param1: Индекс клиента, который выбрал пункт
      • param2: Индекс пункта, который выбрал клиент
    Cancel. Отмена показа меню
    • MenuAction_Cancel в SourcePawn. Это действие срабатывает, не смотря на вызов.
      • param1: Индекс клиента, который отменил показ меню
      • param2: Код причины отмены показа меню
    End. Окончание показа меню
    • MenuAction_End в SourcePawn. Это действие всегда срабатывает, то ли просьба или нет.
      • param1: Причина окончания показа меню
      • param2: Если param1 был MenuEnd_Cancelled, это содержит причину отмены показа меню

Панели
Для панелей, функции обратного вызова всегда меняются. Для SourcePawn, Menu Handle всегда будет INVALID_HANDLE.
Select. Выбор пункта в панели
  • MenuAction_Select в SourcePawn.
    • param1: Индекс клиента, который выбрал пункт
    • param2: Индекс пункта, который выбрал клиент
Cancel. Отмена показа панели
  • MenuAction_Cancel в SourcePawn.
    • param1: Индекс клиента, который отменил показ панели
    • param2: Код причины отмены показа панели

Пример
Разберем создание панели и меню с вопросами
Код:
ваш вопрос 1. ответ 1 2. ответ 2

Меню
PHP код:
// Подключаем библиотеки 
#include <sourcemod> 

// Старт плагина 
public OnPluginStart() 

   
// Регистрируем команду, введя которую нам отобразится меню
   
RegConsoleCmd("menu"Menu


// Обрабатываем команду 
public Action:Menu(clientargs

   
// Создаем Handle меню 
   // MenuHandler - Значит что, нажав на один из пунктов, произойдет дальнейшее действие
   // То есть, нажав к примеру на "Да", нам выведется в консоль о том, что вы выбрали именно этот пункт
   
new Handle:menu CreateMenu(MenuHandler
   
SetMenuTitle(menu"Вы любите Counter-Strike:Source?"
   
AddMenuItem(menu"yes""Да"
   
AddMenuItem(menu"no""Нет"
   
SetMenuExitButton(menufalse
   
DisplayMenu(menuclient20
  
   return 
Plugin_Handled 


public 
MenuHandler(Handle:menuMenuAction:actionparam1param2

   
/* Если пункт меню был выбран, выводим в его консоль об этом */
   
if (action == MenuAction_Select
   { 
      
decl String:info[32
      new 
bool:found GetMenuItem(menuparam2infosizeof(info)) 
      
PrintToConsole(param1"Вы выбрали пункт: %d (Найдено: %d Информация: %s)"param2foundinfo
   } 
   
/* Если клиент отменил показ меню, выводим в консоль сервера */
   
else if (action == MenuAction_Cancel
   { 
      
PrintToServer("Клиент %d Отменил показ меню.  Причина: %d"param1param2
   } 
   
/* Если показ меню закончился, закрываем Handle */
   
else if (action == MenuAction_End
   { 
      
CloseHandle(menu
   } 
}
Обратите внимание на несколько очень важных примечаний
  • Один из пунктов Select или Cancel будет направлен в действие обрабатывания меню
  • Пункт End всегда будет направлен в действие обрабатывания меню
  • Уничтожение меню следует производить только, если клиент отменил меню, или оно закончилось
  • В меню, по умолчанию, есть пункт выхода
  • Продолжительно показа меню зависит от DisplayMenu
 
rootДата: Вторник, 26.03.2013, 15:30 | Сообщение # 2
Генералиссимус
Группа: Администраторы
Сообщений: 561
Статус: Offline
Панель
PHP код:
// Подключаем библиотеки 
#include <sourcemod> 

// Старт плагина 
public OnPluginStart() 

   
// Регистрируем команду, введя которую нам отобразится меню
   
RegConsoleCmd("panel"Panel


// Обрабатываем команду 
public Action:Panel(clientargs

   
// Создаем Handle панели 
   
new Handle:panel CreatePanel(); 
   
SetPanelTitle(panel"Вы любите спать?"
   
DrawPanelItem(panel"Да"
   
DrawPanelItem(panel"Нет"
  
   
SendPanelToClient(panelclientPanelHandler20
  
   
CloseHandle(panel
  
   return 
Plugin_Handled 


public 
PanelHandler(Handle:menuMenuAction:actionparam1param2

   if (
action == MenuAction_Select
   { 
      
PrintToConsole(param1"Вы выбрали пункт: %d"param2
   } 
   else if (
action == MenuAction_Cancel
   { 
      
PrintToServer("Клиент %d отменил показ панели. Причина: %d"param1param2
   } 
}
Некоторые примечания
  • Есть лимит добавления элементов в панель
  • Возможность уничтожения панели после окончания отображения
  • У обработчика всегда есть информация (Отменили показ панели;Выбрали пункт)

Расширенное меню
Теперь рассмотрим более сложный пример. Меню, в котором элементы расположены на нескольких страницах.
Суть плагина: Отображение карт, с последующей сменой при выборе
PHP код:
new Handle:g_MapMenu INVALID_HANDLE 
  
public OnPluginStart() 

   
RegConsoleCmd("menu_changemap"Command_ChangeMap); 

  
public 
OnMapStart() 

   
g_MapMenu BuildMapMenu(); 

  
public 
OnMapEnd() 

   if (
g_MapMenu != INVALID_HANDLE
   { 
      
CloseHandle(g_MapMenu); 
      
g_MapMenu INVALID_HANDLE
   } 

  
Handle:BuildMapMenu() 

   
/* Открытие файла */ 
   
new Handle:file OpenFile("maplist.txt""rt"); 
   if (
file == INVALID_HANDLE
   { 
      return 
INVALID_HANDLE
   } 
  
   
/* Создание Handle меню */ 
   
new Handle:menu CreateMenu(Menu_ChangeMap); 
   new 
String:mapname[255]; 
   while (!
IsEndOfFile(file) && ReadFileLine(filemapnamesizeof(mapname))) 
   { 
      if (
mapname[0] == ';' || !IsCharAlpha(mapname[0])) 
      { 
         continue; 
      } 
      new 
len strlen(mapname); 
      for (new 
i=0i<leni++) 
      { 
         if (
IsCharSpace(mapname[i])) 
         { 
            
mapname[i] = '\0'
            break; 
         } 
      } 
      
/* Проверка на то, что карта действительна */ 
      
if (!IsMapValid(mapname)) 
      { 
         continue; 
      } 
      
/* Добавление в меню */ 
      
AddMenuItem(menumapnamemapname); 
   } 
   
/* Закрытие Handle */ 
   
CloseHandle(file); 
  
   
/* Заголовок */ 
   
SetMenuTitle(menu"Please select a map:"); 
  
   return 
menu

  
public 
Menu_ChangeMap(Handle:menuMenuAction:actionparam1param2

   if (
action == MenuAction_Select
   { 
      new 
String:info[32]; 
  
      
/* Получение информации пункта */ 
      
new bool:found GetMenuItem(menuparam2infosizeof(info)); 
  
      
/* Информация о выборе клиента */ 
      
PrintToConsole(param1"You selected item: %d (found? %d info: %s)"param2foundinfo); 
  
      
/* Смена карты */ 
      
ServerCommand("changelevel %s"info); 
   } 

  
public 
Action:Command_ChangeMap(clientargs

   if (
g_MapMenu == INVALID_HANDLE
   { 
      
PrintToConsole(client"The maplist.txt file was not found!"); 
      return 
Plugin_Handled
   }    
  
   
DisplayMenu(g_MapMenuclientMENU_TIME_FOREVER);
  
   return 
Plugin_Handled
}
 
rootДата: Вторник, 26.03.2013, 15:31 | Сообщение # 3
Генералиссимус
Группа: Администраторы
Сообщений: 561
Статус: Offline
Меню будет выглядеть так
Изображение Изображение Изображение
Примечания
  • Автоматическое отображение или скрытие элементов управления
  • Время, указанное для отображения клиенту меню, не меняется при использовании меню
  • Позиции элементов управления не могут быть изменены

Голосование
Голосование в SourceMod имеет сходные черты с меню
  • MenuAction_VoteStart. Начало голосования
  • MenuAction_VoteEnd. Конец голосования. Клиенты отменили, проголосовали или оставили не выбрали один из элементов
  • MenuAction_VoteCancel. Клиент отменил показ голосования. Причина отмены будет содержаться в параметре param1
Стоить отметить некоторые примечания

  • Выбор отключившегося клиента недействителен
  • Результаты голосования вы должны самостоятельно получать

Простое голосование
PHP код:
public Handle_VoteMenu(Handle:menuMenuAction:actionparam1param2

   if (
action == MenuAction_End
   { 
      
/* Закрытие Handle, если меню стало неактивным */
      
CloseHandle(menu); 
   } else if (
action == MenuAction_VoteEnd) { 
      
/* 0 = Да, 1 = Нет */ 
      
if (param1 == 0
      { 
         new 
String:map[64
         
GetMenuItem(menuparam1mapsizeof(map))
         
ServerCommand("changelevel %s"map); 
      } 
   } 

  
DoVoteMenu(const String:map[]) 

   if (
IsVoteInProgress()) 
   { 
      return; 
   } 
  
   new 
Handle:menu CreateMenu(Handle_VoteMenu
   
SetMenuTitle(menu"Сменить карту на %s?"map
   
AddMenuItem(menumap"Да"
   
AddMenuItem(menu"no""Нет"
   
SetMenuExitButton(menufalse
   
VoteMenuToAll(menu20); 
}
Расширенное голосование
PHP код:
public Handle_VoteMenu(Handle:menuMenuAction:actionparam1param2

   if (
action == MenuAction_End
   { 
      
/* Закрытие Handle */ 
      
CloseHandle(menu); 
   } 

  
public 
Handle_VoteResults(Handle:menu
         
num_votes
         
num_clients
         const 
client_info[][2], 
         
num_items
         const 
item_info[][2]) 

   
/* Поиск элемента, набравшего больше всего голосов */
   
new winner 0
   if (
num_items 
       
&& (item_info[0][VOTEINFO_ITEM_VOTES] == item_info[1][VOTEINFO_ITEM_VOTES])) 
   { 
      
winner GetRandomInt(01); 
   } 
  
   new 
String:map[64
   
GetMenuItem(menuitem_info[winner][VOTEINFO_ITEM_INDEX], mapsizeof(map)) 
   
ServerCommand("changelevel %s"map

  
DoVoteMenu(const String:map[]) 

   if (
IsVoteInProgress()) 
   { 
      return; 
   } 
  
   new 
Handle:menu CreateMenu(Handle_VoteMenu
   
SetVoteResultCallback(menuHandle_VoteResults
   
SetMenuTitle(menu"Сменить карту на %s?"map
   
AddMenuItem(menumap"Да"
   
AddMenuItem(menu"no""Нет"
   
SetMenuExitButton(menufalse
   
VoteMenuToAll(menu20); 
}

Перевод фраз в голосовании

PHP код:
public Handle_VoteMenu(Handle:menuMenuAction:actionparam1param2

   if (
action == MenuAction_End
   { 
      
/* Закрытие Handle */ 
      
CloseHandle(menu); 
   } else if (
action == MenuAction_VoteEnd) { 
      
/* 0=yes, 1=no */ 
      
if (param1 == 0
      { 
         new 
String:map[64
         
GetMenuItem(menuparam1mapsizeof(map))
         
ServerCommand("changelevel %s"map); 
      } 
   } else if (
action == MenuAction_DisplayItem) { 
      
/* Получение строки в меню, после получения будем его использовать как фразу для перевода */
      
decl String:display[64]; 
      
GetMenuItem(menuparam2""0_displaysizeof(display)); 
  
      
/* Перевод текста, отображенный клиенту */ 
      
decl String:buffer[255]; 
      
Format(buffersizeof(buffer), "%T"displayparam1); 
  
      return 
RedrawMenuItem(buffer); 
   } else if (
action == MenuAction_Display) { 
      
/* Handle панели является вторым параметром */
      
new Handle:panel Handle:param2
  
      
/* Получение имени карты */ 
      
decl String:map[64]; 
      
GetMenuItem(menu0mapsizeof(map)); 
  
      
/* Фраза для перевода */ 
      
decl String:buffer[255]; 
      
Format(buffersizeof(buffer), "%T""Change map to?"clientmap); 
  
      
SetPanelTitle(panelbuffer); 
   } 

  
DoVoteMenu(const String:map[]) 

   if (
IsVoteInProgress()) 
   { 
      return; 
   } 
  
   new 
Handle:menu CreateMenu(Handle_VoteMenuMenuAction_DisplayItem|MenuAction_Display
   
SetMenuTitle(menu"Сменить карту на %s?"map
   
AddMenuItem(menumap"Да"
   
AddMenuItem(menu"no""Нет"
   
SetMenuExitButton(menufalse
   
VoteMenuToAll(menu20); 
}
Оригинал
 
Форум » Форум » Уроки SourceMod (SourcePawn) Скриптинга » Создание меню в SourcePawn (http://forum.sn-project.ru/viewtopic.php?f=75&t=2045)
  • Страница 1 из 1
  • 1
Поиск: