- Статьи
- 2018-12-28
Не будем рассказывать о "вступлении" в программировании, о работе процессора, процесса компиляции и интерпретации ( or трансляции ) программы, а сразу попытаемся практично подойти к понятию программировании в Pawn
P.S
Если вы желаете больше влиться в мир программ, советую изучить следующие темы:
Ну что же, давайте разбирать простейший плагин написанный на Pawn для CS 1.6 ( я решил взять броню, ибо считаю здесь есть всё для простого описания )
#include <amxmodx>
#include <fakemeta>
#include <zombieplague>
#define MAX_IN_ROUND 4 // Максимум в раунде
const g_item_cost = 15 // Цена
new const g_sound_buyarmor[] = { "items/tr_kevlar.wav" } // присваиваем константе массиву значение ( строку ) путь до звука
const g_armor_amount = 250 // Покупка за 1 раз
const g_armor_limit = 250 // Лимит
new g_armor_counter[33] = 0 // все 32 значения массива ( счёт начинается с 0 ) будут при компиляции/старта плагина равны 0
new extra_armor[512] // объявление массива
new g_itemid_humanarmor // объявление переменной
public plugin_precache()
{
precache_sound(g_sound_buyarmor) // кэшируем звук покупки
}
public plugin_init()
{
register_plugin("[ZP] Extra-Item: Anti-Infection Armor", "1", "Dambas") // регистрируем плагин
register_event("ResetHUD","Start_round","be") // регистрируем событие смены худов CS
formatex(extra_armor, charsmax(extra_armor), "%L", LANG_SERVER, "EXTRA_ARMOR"); // в массив extra_armor засовываем значение из lang файла которое равно EXTRA_ARMOR
g_itemid_humanarmor = zp_register_extra_item(extra_armor , g_item_cost, ZP_TEAM_HUMAN) // присваиваем переменной возвращаемое значение функции
register_dictionary("zombie_plague.txt"); // регистрируем lang файл
}
public Start_round(id)
{
g_armor_counter[id] = 0 // обнуляем лимит покупок у всех игроков в начале раунда
}
public zp_extra_item_selected(id, itemid) // описываем "форвард" для нашего плагина
{
if (itemid == g_itemid_humanarmor) // проверка на то, что если мы выбрали предмет из нашего плагина
{
if (g_armor_counter[id] > MAX_IN_ROUND) // если лимит покупок у игрока не выше того, что мы указали в MAX_IN_ROUND продолжаем идти дальше
{
ColorChat(id, "!g[ZP] !yТы купил максимум брони!" ) // вызываем функцию которая отобразит сообщение игроку
return ZP_PLUGIN_HANDLED // прекращаем данную функцию + возвращаем деньги игроку
}
else
{
set_pev(id, pev_armorvalue, float(min(pev(id, pev_armorvalue)+g_armor_amount, g_armor_limit))
// Мы выберем минимальное ( min() ) значение из [b]значений броня игрока+количетсво покупаемой брони[/b] pev(id, pev_armorvalue)+g_armor_amount и [b]максимальное количество брони[/b]
[b] // То есть, у игрока не может быть брони больше, чем то, что мы указали в g_armor_limit[/b]
engfunc(EngFunc_EmitSound, id, CHAN_BODY, g_sound_buyarmor, 1.0, ATTN_NORM, 0, PITCH_NORM) // воспроизводим звук указанный в массиве g_sound_buyarmor
g_armor_counter[id]++ // уменьшаем для игрока [id] его лимит
ColorChat(id, "!g[ZP] !yТы купил !g250 брони!" ) // вызываем функцию для вывода сообщению игрока
}
}
return PLUGIN_HANDLED // заканчиваем работу функции
}
stock ColorChat(const id, const input[], any:...) // тут много сложного для новичков
{
new count = 1, players[32] // создаем переменную и массив для игроков
static msg[191] // создаём статичную переменную, чтобы её значение не удалялось после окончания функции
vformat(msg, 190, input, 3) // из массива с любым размером в массив msg с размером 191
replace_all(msg, 190, "!g", "^4") // меняем все !g на ^4
replace_all(msg, 190, "!y", "^1") // меняем все !y на ^1
replace_all(msg, 190, "!t", "^3") // меняем все !t на ^3
if (id) players[0] = id; else get_players(players, count, "ch") // если id не 0, то в в ячейку массива players[0] кидаем id игрока ( для будущего вывода сообщения именно ему ), ИНАЧЕ получаем id всех игроков для будущего вывода всем игрокам
{
for(new i = 0; i < count; i++) // цикл от 0 до количество игроков
{
if(is_user_connected(players[i])) // проверяем на коннект игрока ( антикраш )
{
message_begin(MSG_ONE_UNRELIABLE, get_user_msgid("SayText"), _, players[i]) // запускаем сообщение, с параметром вывода текста
write_byte(players[i]) // кому выводим
write_string(msg) // что выводим
message_end() // заканчиваем сообщение
}
}
}
}
В любой программе есть 3 блока:
Переменная.
В любой программе можно объявлять переменные. Они могут быть глобальными, и локальными. Разница в том, что к глобальным переменным можно обращаться из любой части кода, а к локальным только в том, где они объявлены.
Так же, у любой переменной, есть свои свойства, а именно:
- тип данных
- значение
- адрес
- имя
Чтобы при объявлении сразу присвоить значения, используется оператор "=": new ИмяПеременной = 10;
Чтобы принудительно задать тип переменной, нужно использовать структуру: new ТипДанных:ИмяПеременной.
Список возможных типов переменной:
- Integer - целочисленный
- Float - дробный ( пример: 0.045 )
- Bool - логический ( либо true, либо false ВАЖНО: Не 0, или 1 )
- Array - массив
P.S
Нельзя забывать про так называемые "инструкции". Через них тоже можно объявлять переменные которые можно использовать в коде. Они схожи с константами, но их основное отличие, что во время компиляции они лишь заменяют своё имя, на их значение в коде
Структура объявления: #define ИМЯ_ПЕРЕМЕННОЙ ЗНАЧЕНИЕ
#define MYNAME Player
Массивы.
Следующая структура, которую нужно понимать для программирования в Pawn. Массив, грубо говоря, строка из переменных, у которых есть свой адрес и значение.
Для объявления массива, используются структура: new ИмяМассива[РазмерМассива];
В любом языке программирования, так же можно объявить двумерный массив, это, опять же грубо говоря, таблица, в которой в каждой ячейке массива - хранится адрес другого массива. Общую структуру такого массива можно представить как таблицу
new TutMassiv[3][3];
for(new i=0; i < 3; i++)
for(new k=0; k < 3; i++)
TutMassiv[i][k] = i;
TutMassiv[0][0] =0 | TutMassiv[1][0] =0 | TutMassiv[2][0] =0 |
TutMassiv[0][1] =1 | TutMassiv[1][1] =1 | TutMassiv[2][1] =1 |
TutMassiv[0][2] =2 | TutMassiv[1][2] =2 | TutMassiv[2][2] =2 |
new tut[3] = { 5, 4, 10 }; - одномерный массив
new tutD[2][2] = { { 3, 2 }, { 4, 6 } }; - двумерный массив ( таблица )
new tutT[3][3][3] =
{
{
{1, 2, 3}, {4, 5, 6}, {7, 8, 9}
},
{
{1, 2, 3}, {4, 5, 6}, {7, 8, 9}
},
{
{1, 2, 3}, {4, 5, 6}, {7, 8, 9}
}
}; - трёхмерный массив ( пространство )
Функции.
Еще одна важнейшая часть для осознания Pawn'а. Функции нужны для того, чтобы не повторять много раз одни и те-же куски кода, а отделить их отдельным именем и вызывать при необходимости.
Например, вам нужно при убийстве игрока, давать ему броню, здоровье, уровень и еще много много бонусов. Чтобы не загрязнять код, лучше вызывать одну функцию в событии убийства.
Все функции в Pawn должны начинаться со слова public. Общая структура написания функций: public ИмяФункции(Атрибут, Атрибут2, Атрибут3, ..., АтрибутN) { описании функции )
Чтобы вызвать функцию, нужно просто написать её имя, и отослать туда какие либо данные - атрибуты. Имена атрибутов, могут не совпадать с именами переменных которые вы туда отправляете ( НО! Типы должны обязательно совпадать, так как вы не можете присвоить типу bool тип Integer, это вызовет Warning 213 при компиляции )
public NameFunction(id, Health, Armor) // Описание функции
{
set_user_health(id, Health);
set_user_armor(id, Armor);
}
// code
NameFunction(id, 300, 300); // Вызов функции
// code
Циклы.
Нужны для автоматического повтора каких либо действий при совпадении определенного условия.
Существует 3 вида циклов:
- for(идентификация счетчика; условие; инкремент ( прибавление значение счетчика ))
- while(условие)
- do{ реализация кода }while(условие)
break - останавливает выполнения цикла
continue - переходит на следующий шаг цикла
Как это работает
- Цикл For
for(new i=0; i < 5; i++) { Тело Цикла }
Сначала мы объявляем локальную переменную i и присваиваем ей значение 0. Эта локальная переменная будет использоваться только внутри тела цикла. Можно использовать и не локальные переменные написав её внутри for без оператора new и присваивания.
После инициализации счетчика, мы проверяем условие. Если i < 5, начинаем выполнять операции находящиеся внутри тела цикла. После последней операции цикла, мы добавляем к существующему значению i единицу ( т.е. i = i + 1 ). Это и описано в инкременте счетчика(..; i++)
После чего снова идёт условие. - Цикл while(i<5) { Тело Цикла }
Здесь всё так же, только нам придётся внутри тела цикла самому увеличивать значение i. Цикл будет работать, пока условие в скобках после while будет выполняться - Цикл do{ Тело Цикла }while(условие)
Этот цикл, отличается от других тем, что сначала мы выполняем операции в теле цикла, а только потом проверяем условия, и если оно верно, то снова выполняем операции до момента пока условие не сработает.
Операция Ветвления - if(){} else if(){} else{}
Операции ветвления, или условные операции, самое частое и нужное в программировании. Они нужны для проверки какого либо условия и дальнейшего выполнения или изменения условия.
Обязательная структура:
if(условие) // ЕСЛИ ...
{
Операции
}
else if(условие) // ИНАЧЕ ЕСЛИ...
{
}
..... // здесь может быть сколько угодно структур else if(условие)
else if(условие)
{
Операции
}
else // ИНАЧЕ .... - выполняется, если не одно из else if не выполнилось
{
Операции
}
Если не одна операция ветвления не совпала с условием, и операции else нету, то ВСЯ операция ветвления просто игнорируется и код идёт дальше Функция public plugin_init(), и посмотрим, что делает каждая строчка
public plugin_init() // Функция которая вызывается при компиляции плагина или запуска сервера
{
register_plugin("[ZP] Extra-Item: Anti-Infection Armor", "1", "Dambas") // Регистрация плагина, и присваивание ему имени
register_event("ResetHUD","Start_round","be") // Регистрация события, и присваивания ему в данном плагине функции ( в данном случае ResetHUD )
formatex(extra_armor, charsmax(extra_armor), "%L", LANG_SERVER, "EXTRA_ARMOR"); // formatex - функция работы со строкой, далее мы рассмотрим её поближе
g_itemid_humanarmor = zp_register_extra_item(extra_armor , g_item_cost, ZP_TEAM_HUMAN) // Переменная как значение функции. Далее мы рассмотрим зачем это нужно
register_dictionary("zombie_plague.txt"); // Подключение lang-файла для русификации плагина
}
Я собрал все нужные для новичка события для создания функций их реализации:
- register_event - регистрирует некоторые из стандартных событий Half-Life. Полный список тут - События Half-Life
- register_logevent - регистрирует события которые обычно пишутся в логах. Нам нужны чаще всего для начала и конца раунда
- RegisterHam - не побоюсь для новичков сказать, что это нужно для того, чтобы отловить какое то событие. Но функционал намного выше. Нам чаще всего нужно для событий получение урона, смерти, спавна и других. Удобность - наличие id игрока
- register_touch - если углубитесь в тему Pawn'а, то эта функция поможет вам отловить событие касание объектов друг об друга
Функция plugin_precache(), нужна для кэширования ваших ресурсов ( модели, звуки, спрайты ) на сервере и в дальнейшем для передачи их игроку.
Внутри данной функции можно использовать несколько функций кэширования ( разных библиотек )
Fakemeta: engfunc(имя константы fakemeta, имя кэшируемой переменной)
- Константа EngFunc_PrecacheModel - для кэширования модели или спрайта. Пример: engfunc(EngFunc_PrecacheModel, Model)
- Константа EngFunc_PrecacheSound - для кэширования звука. Пример engfunc(EngFunc_PrecacheSound, Sound)
- precache_model
- precache_sound
FAQ: ( ЧАСТО ЗАДАВАЕМЫЕ ВОПРОСЫ НОВИЧКОВ )
- С чего начать писать плагин, на что смотреть, что делать если я не понимаю как работает код
&Я не понимаю как работает код&
Для начала, посмотрите на название переменных и событиях описанных в public plugin_init()
Поймите структуру программы, какие функции вызываются первыми, какие используются чаще, какие важные. По смыслу вы сможете понять, в каком месте кода вы должны искать.
Например: Вопрос: Мне нужно в определенном плагине, изменить радиус взрыва ракеты.
Для начала, мне нужно найти функцию, которая отвечает зазапуск самой ракеты. Потом найти, функцию которая отвечает за взрыв ракеты. После чего найти структуру message_begin, ведь скорее всего именно в ней указывается радиус взрыва
&С чего начать писать плагин&
Продумайте в голове все свои мысли. Изобразите структуру вашего плагина на листочке или в Paint ( если вы собрались браться за что то большое ). Потом обдумайте, какие библиотеки ваш лучше использовать. Если вы намереваетесь писать плагин связанный как либо внутри-игровыми объектами: задумайтесь что будет лучше, использовать модуль engine или fakemeta (изучите их для начала). Подумайте, как будут использоваться переменные, какие функции вы распишите, какие события затронете.
- Чем отличается (id) от [id]
Всё, что находится в круглых скобках - это вызов функции. Квадратные скобки - обращение к ячейки массива с идентификатором указанным внутри []
То есть, set_user_health(id, Health) -> мы отправляем в функции число которое постоянно хранится в id
А users[id] -> мы обращаемся к массиву users по номеру который записан в id
Ни в коем случае не путайте!
- Как исправлять Warning'и
Начнем с того, что ошибки(error) и предупреждения(warning) - это разные вещи. Если в вашем плагине ошибка - он не скомпилируется. Если предупреждения - скомпилируются, но компилятор вас предупредит, что в каком то месте допущена синтаксическая ошибка, которая может фатально или не очень повлиять на работу сервера.
Всё зависит от самого Warning'а. Обычно, переведя его содержания и посмотрев на строчку которая его вызвала - вы сами всё поймете.
Но не со следующими:
Warning 217, Warning 213 - иногда новички конкретно зависают над этими предупреждениями.
Ну что же, давайте рассмотрим возможные варианты их появления - %Warning 213%
Тут может быть несколько вариантов. Чаще всего, предупреждение о не соответствии тэгов появляется когда функция принимает переменную одного типа, а вы отправляете другой
К примеру. Когда вы работаете с уроном, вы должны понимать, что любой урон в игре имеет тип Float. Поэтому работая с ним, вы либо при вызове функций должны сами присваивать ему тип Float, либо везде держать его в дробном состоянии
Нашел хороший пример:
set_pev(iPlayer, pev_velocity, Float:{0.0,0.0,0.0})
В данной функции при её вызове, вы сами должны указать тип Float, чтобы не столкнуться с проблемой 213 предупреждения. - &Warning 217&
Тут 2 варианта. Либо у вас не выровнены отступы ( где то Табулирование, где то лишние пробелы ), либо неправильная структура кода
К неправильной структуре я отношу забытые фигурные скобки
Запомните, в функциях ветвления и циклах, не использовать фигурные скобки можно только в ситуации, когда в теле цикла или ветвления используется только одна операция, то есть// Правильно if(X>5) a = 3; else a = 5;; // Неправильно if(X>5) a = 3; b = 6; else a = 5;
30%
Скидка на покупку всех
сборок до 30.06.2025
Специально для тебя - Гость
Выбрать сборку
[ZP 4.3] Extra Item: Buff M-249 (Pheonix) [FREE AMXX | SMA]
Красавачик Очень хороший плагин,пригодился
[ZP] Extra Item - Stun Rifle [MKOD]
Красава Оченьхороший плагин Красава Оченьхороший плагин чКрасава Оченьхороший плагин
Сборка сервера Zombie CSO + LVL
send me free please?
GameCMS Установка Настройка (Платная)
hello bro nice skin
[ZP] Extra Item - M4a1 Frost
how take weapon cmd ?
Данные для Связи.https://vk.com/id344641190 https://t.me/SysTemmmmmm Discord: Wizard#2169Услуга Помощь в установке/настройке серверов/модов/плагинов/сайтов.
GameCMS (Game Content Management System) Данные для Связи. https://vk.com/id344641190 https://t.me/SysTemmmmmm Discord: Wizard#2169
Исправили Почту всех приходит, Очистили базу от кометов, Мусорных файлов, Дальше будем работать по файлам.
ReHLDS (Reverse-engineered) - это новый шаг вперед, который дает второе дыхание нашим серверам. ReHLDS работает в 2 раза быстрей, чем HLDS.
AMXModX - это Metamod дополнение, которое позволяет создавать новые модификации для Half-Life на языке Pawn
Reunion является продолжением Dproto для ReHLDS. Это metamod плагин, который позволяет заходить 47/48 Non-Steam на сервер.
Revoice - это Metamod plugin, который дает возможность общения голосовым чатом между non-steam и steam клиентами.
Новый Metamod-r содержит огромное количество оптимизаций производительности и намного более чистый код. Ядро было написано с использованием JIT-компилятора.
Ultimate Unprecacher являет плагином для MetaMod, работает он по принципу отключение не нужных ресурсов на вашем сервере, тем самым вы сможете освободить места для ресурсов под ваши плагины, с помощью данного модуля можно избавиться от ошибки 512!
ReAuthCheck - это Metamod плагин, который занимается проверкой ваших игроков на валидность, с помощью данного модуля для REHLDS вы сможете защитить свой сервер от ботов, которые постоянно спамят рекламу или просто забивают слот на сервере!
NetBufExtender или NBEX - это метамод-плагин, который расширяет "интернет-буфер": буферы сервера и клиента(гарантия не 100%). Расширяет до 64 кб. Это значит, что у игроков уменьшается вероятность быть кикнутыми с ошибкой "Reliable channel overflowed".
UINO — metamod-плагин, который позволяет удалять ненужные поля из userinfo(setinfo) когда движок передаёт его другим игрокам на сервере. Данная мера уменьшает объём передаваемых данных и немного сокращает шанс быть кикнутым с "Reliable channel overflowed".