Помощь новичку или PAWN для всех.

Сообщения
13
Реакции
11
Здравствуйте уважаемые пользователи Dev-CS.ru .
В данном разделе я хочу получать от вас дельные советы и помощь по языку PAWN, но хочу сделать так чтобы не только я получал это все, но и ОСТАВШАЯСЯ часть пользователей не знающие данный язык.


Прошу не сраться и не бомбить тут т.к я сам новичок в данном языке и хочу также помочь понять этот язык другим людям не понимающих его.

В основном советую использовать такие редакторы как NotePad++ или AMXX Studio

Ну пожалуйста можно и начать.

С чего можно начать это с простейшего меню.

И так поехали :)

1. Для начала нужно подключать с помощь дерективы #include библиотеку <amxmodx>

Что такое деректива #include ?
Директива #include позволяет включать в текст программы указанный файл. Если файл является стандартной библиотекой и находится в папке компилятора, он заключается в угловые скобки <>.
Как это должно выглядить в вашем редакторе.
#include <amxmodx>

2. Следующим пунктом нам нужно создать функцию
C++:
public plugin_init()
{
    Какие-то вызываемые части плагина
}
Для чего она нужна ?
В данной функции происходит добавление каждой функции. Т.е получается, что функция plugin_init() это фундамент для каждого плагина.
Не один плагин не сможет обойтись без нее.

В общем виде у вас должно получится так
C++:
#include <amxmodx>

public plugin_init()
{
    Какие-то вызываемые части плагина
}
Что такое public?
Это внешная или публичная функция которая доступна Amx Mod X движку.


C++:
/**
* Called just after server activation.
*
* @note Good place to initialize most of the plugin, such as registering
*       cvars, commands or forwards, creating data structures for later use, or
*       generating and loading other required configurations.
*
* @noreturn
*/
forward plugin_init();
3. Регистрируем наши первые элементы в plugin_init().

В первую очередь мы добавим вот такую функцию.
register_plugin("Название плагина", "Его номер или версия как вам удобно", "Автор плагина т.е вы");


C++:
/**
* Sets informations about the calling plugin.
*
* @param plugin_name   Name of the plugin
* @param version       Version of the plugin
* @param author        Author of the plugin
*
* @return              Plugin id of the calling plugin
*/
native register_plugin(const plugin_name[], const version[], const author[]);
Что она дает ?
Эта функция регистрирует информацию о вашем плагине. Т.е если в консоли сервера набрать amxx list вы увидеть данную информацию, но это все будет рассматриваться в последующих частях.

В целостности это выглядит так
C++:
#include <amxmodx>

public plugin_init()
{
    register_plugin("First Menu", "0.1", "By PyRoKiNeS)
}
First Menu - Название плагина. Вы можете дать любое название своему плагину
0.1 - Номер или версия плагина. Вы так же можете дать любой номер или любую версию для ваше плагина
By PyRoKiNeS - Автор плагина. Вы указываете себя.

Следующим делом нам надо сделать так чтобы наше меню можно было открыть. В наш код добавляется следующая функция register_clcmd.

C++:
/**
* Registers a callback to be called when the client executes a command from the
* console.
*
* @note For a list of possible access flags, see the ADMIN_* constants in
*       amxconst.inc
* @note Opting in to FlagManager enables the admin privileges to be overwritten
*       by the end user via the cmdaccess.ini config file.
* @note Automatic detection for FlagManager will only include a command if it
*       has required privileges (flags is not -1) and it is not a command
*       starting with "say".
*
* @param client_cmd    Command to register
* @param function      Callback function
* @param flags         Admin privilege flags required
* @param info          Command description
* @param FlagManager   0 opts out of flag manager, 1 opts in, -1 selects
*                      automatically
* @param info_ml       If true, the parameter "info" will be looked up as multilingual key
*
* @return              Command id, 0 on failure
* @error               If an invalid callback function is specified, an error
*                      will be thrown.
*/
native register_clcmd(const client_cmd[], const function[], flags = -1, const info[] = "", FlagManager = -1, bool:info_ml = false);
const client_cmd[] - команда для клиента. Может давать любую.
const function[] - функция которая будет вызываться по команде клиента. Может так же дать любое название.
flags - права на данную функцию.

С помощью данной функцию мы сможем создать команду для клиента которая будет открывать наше меню.
В коде она должна выглядеть так
C++:
#include <amxmodx>

public plugin_init()
{
    register_plugin("First Menu", "0.1", "By PyRoKiNeS")
    register_clcmd("say /menu", "ClCmd_Menu", 0)
    register_clcmd("say_team /menu", "ClCmd_Menu", 0)
    register_clcmd("menu", "ClCmd_Menu", 0)
}
4. Появление нашей public функции в коде.
После того как мы создали register_clcmd с функцией ClCmd_Menu или ту которую вы дали в наш код добавляется
C++:
public ClCmd_Menu(id)
{
    Тут явно что-то будет :)
}
Т.е по команде /menu сработает функция ClCmd_Menu.
Полноценно выглядит так

C++:
#include <amxmodx>

public plugin_init()

{
    register_plugin("First Menu", "0.1", "By PyRoKiNeS")
    register_clcmd("say /menu", "ClCmd_Menu", 0)
    register_clcmd("say_team /menu", "ClCmd_Menu", 0)
    register_clcmd("menu", "ClCmd_Menu", 0)
}

public ClCmd_Menu(id)
{
    Тут явно что-то будет :)
}
5. Создание самого меню.
Пришло время создать само меню для наших игроков.
В функции ClCmd_Menu создаем переменную:
new i_Menu
Вместо i_Menu может дать любое название.
Следующим делом присваиваем ей функцию menu_create

Что вообще делает эта функция?
Данная функция создает меню, но не показывает его игрокам.


C++:
/**
* @brief Creates a new menu object.
*
* The handler function should be prototyped as:
*
* public <function>(id, menu, item)
*  id     - Client the menu is being acted upon.
*  menu   - Menu resource identifier.
*  item   - Item the client selected.  If less than 0, the menu was
*           cancelled and the item is a status code.  menu_display
*             should never be called immediately if the item is a status
*             code, for re-entrancy reasons.
*
* The handler function should always return PLUGIN_HANDLED to block
* any old menu handlers from potentially feeding on the menu, unless
* that is the desired functionality.
*
* @param title         Title the menu should use.
* @param handler        Name of the handler function.  The function will be invoked
*                        once and only once to every menu_display() call.
* @param ml            Unused (should be 0).
* @return                Menu resource identifier which must be destroyed via
*                        menu_destroy().  All menus are destroyed when the plugin
*                        unloads.
* @error                Function name not found.
*/
native menu_create(const title[], const handler[], ml=0);
const title[] - Это наш заголовок меню
const handler[] - Функция обработчика которая будет вызываться при выборе пункта меню.
ml=0 - Она постоянно будет ноль (бесполезная информация с официального сайта)

В коде это выглядит вот так:

C++:
#include <amxmodx>

public plugin_init()

{
    register_plugin("First Menu", "0.1", "By PyRoKiNeS")
    register_clcmd("say /menu", "ClCmd_Menu", 0)
    register_clcmd("say_team /menu", "ClCmd_Menu", 0)
    register_clcmd("menu", "ClCmd_Menu", 0)
}

public ClCmd_Menu(id)
{
    new i_Menu = menu_create("\r[Меню] \wГлавное меню", "menu_handler")
}
Следующим делом создаем пункты для меню.
После функции menu_create добавляем menu_additem
C++:
/**
* Adds an menu to a menu.
*
* @param menu            Menu resource identifier.
* @param name            Item text to display.
* @param info            Item info string for internal information.
* @param paccess        Access required by the player viewing the menu.
* @param callback        If set to a valid ID from menu_makecallback(), the
*                        callback will be invoked before drawing the item.
* @noreturn
* @error                Invalid menu resource.
*/
native menu_additem(menu, const name[], const info[]="", paccess=0, callback=-1);
menu - Идентификатор меню. Т.е в какое меню добавить пункт
const name[] - Имя пункта меню то, что увидит игрок
const info[]="" - Передача информации от пункта меню к функции обработчику
paccess=0 - Флаг доступа к данному пункту меню
callback=-1 - Если используется callback, то указывается его глобальный идентификатор или -1 если нет.

Т.е данная функция создаем пункт в меню.
В коде это выглядит так:

C++:
#include <amxmodx>

public plugin_init()

{
    register_plugin("First Menu", "0.1", "By PyRoKiNeS")
    register_clcmd("say /menu", "ClCmd_Menu", 0)
    register_clcmd("say_team /menu", "ClCmd_Menu", 0)
    register_clcmd("menu", "ClCmd_Menu", 0)
}

public ClCmd_Menu(id)
{
    new i_Menu = menu_create("\r[Меню] \wГлавное меню", "menu_handler")
  
    menu_additem(i_Menu, "Обнулить счет", "1", 0)
    menu_additem(i_Menu, "Статистика", "2", 0)
}
Теперь нам надо добавить пункт с названием Выход.
После функции
menu_additem нужно добавить menu_setprop
C++:
/**
* Sets a menu property.
*
* @param menu            Menu resource identifier.
* @param prop            MPROP_ constant.
* @param ...            Property parameters.
* @return                1 on success, 0 on failure.
* @error                Invalid menu resource or property.
*/
native menu_setprop(menu, prop, ...);
menu - Идентификатор меню
prop - Константа свойства
Сами константы:
C++:
#define MPROP_BACKNAME    2        Создает пункт назад
#define MPROP_NEXTNAME    3        Создает пункт дальше
#define MPROP_EXITNAME    4        Создает пункт выход
В коде это выглядит так:

C++:
#include <amxmodx>

public plugin_init()

{
    register_plugin("First Menu", "0.1", "By PyRoKiNeS")
    register_clcmd("say /menu", "ClCmd_Menu", 0)
    register_clcmd("say_team /menu", "ClCmd_Menu", 0)
    register_clcmd("menu", "ClCmd_Menu", 0)
}

public ClCmd_Menu(id)
{
    new i_Menu = menu_create("\r[Меню] \wГлавное меню", "menu_handler")
  
    menu_additem(i_Menu, "Обнулить счет", "1", 0)
    menu_additem(i_Menu, "Статистика", "2", 0)
  
    menu_setprop(i_Menu, MPROP_EXITNAME, "Выход")
}
После этого нам надо чтобы игроки выдели это меню.
После menu_setprop добавляем menu_display
C++:
/**
* Displays a menu to one client.  This should never be called from a handler
* 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, time=-1);
id - Индекс игрока
menu - Идентификатор меню
page - Номер страницы меню, с какой необходимо открыть меню.

В коде выглядит так:
C++:
#include <amxmodx>

public plugin_init()

{
    register_plugin("First Menu", "0.1", "By PyRoKiNeS")
    register_clcmd("say /menu", "ClCmd_Menu", 0)
    register_clcmd("say_team /menu", "ClCmd_Menu", 0)
    register_clcmd("menu", "ClCmd_Menu", 0)
}

public ClCmd_Menu(id)
{
    new i_Menu = menu_create("\r[Меню] \wГлавное меню", "menu_handler")
  
    menu_additem(i_Menu, "Обнулить счет", "1", 0)
    menu_additem(i_Menu, "Статистика", "2", 0)
  
    menu_setprop(i_Menu, MPROP_EXITNAME, "Выход")
  
    menu_display(id, i_Menu, 0)
}
И последним делом нам нужно создать обработчик меню который будет присваивать команды к каждому пункту в меню.
C++:
public menu_handler(id, menu, item)
{
    if( item < 0 )
    return PLUGIN_CONTINUE;

    new cmd[3], access, callback;
    menu_item_getinfo(menu, item, access, cmd,2,_,_, callback);

    new Choise = str_to_num(cmd)
    switch (Choise)
    {
        case 1:
        {
            client_cmd(id, "say /rs")
        }
        case 2:
        {
             client_cmd(id, "say /stats")
        }
    }
    return PLUGIN_HANDLED;
}
Все оставшиеся функции в menu_handler разберем в следующей части.

Прошу подправить если где-то я ошибся и указать на мои ошибки.
 
Последнее редактирование модератором:
Сообщения
2,144
Реакции
1,223
Помог
44 раз(а)
Довольно хороший мануал, но есть замечания по поводу ошибок в тексте (не в коде) и в самом оформлении. Не стоит весь текст делать жирным! Жирным необходимо выделять слова или предложения, на которые стоит обратить особое внимание.
 
Сообщения
13
Реакции
11
Довольно хороший мануал, но есть замечания по поводу ошибок в тексте (не в коде) и в самом оформлении. Не стоит весь текст делать жирным! Жирным необходимо выделять слова или предложения, на которые стоит обратить особое внимание.
Я вас услышал. В следующий раз постараюсь оформить получше.
 
Сообщения
658
Реакции
462
Помог
10 раз(а)
Minni, по-моему наоборот так даже лучше. Читаешь то о чем говорит автор, затем посматриваешь вскользь примеры - Намного приятнее чем все будет слипаться, по крайней мере в этой ситуации
 
Сообщения
576
Реакции
1,003
Помог
18 раз(а)
menu_destroy() где?
 
Сообщения
576
Реакции
1,003
Помог
18 раз(а)
PyRoKiNeS, при вызове menu_create() вы выделяете память в ядре амхх, если меню не глобальное, то после вызова handler'a память нужно очистить. Если не будете чистить, то с каждым вызовом команды на показ меню вы засоряете память. Сложные меню за карту с активным использованием сожрут у вас много ОЗУ, если совсем не приведут к крашу.
Т.е. как минимум в любой ветке завершения handler'a должен быть вызов menu_destroy()
 
Сообщения
13
Реакции
11
PyRoKiNeS, при вызове menu_create() вы выделяете память в ядре амхх, если меню не глобальное, то после вызова handler'a память нужно очистить. Если не будете чистить, то с каждым вызовом команды на показ меню вы засоряете память. Сложные меню за карту с активным использованием сожрут у вас много ОЗУ, если совсем не приведут к крашу.
Т.е. как минимум в любой ветке завершения handler'a должен быть вызов menu_destroy()
Благодарю. Теперь понял для чего она нужна.
 

Пользователи, просматривающие эту тему

Сейчас на форуме нет ни одного пользователя.
Сверху Снизу