AMX Mod X: уроки по Pawn
1 месяц, 2 недели назад | 0 ОтветыТема закреплена. Технический разбор — в первом сообщении. Вопросы и обсуждение — в ответах ниже.
11. Уроки по скриптингу (Pawn)
Материалы уроков по скриптингу:Дополнительно полезны официальные гайды AlliedModders: Scripting (AMX Mod X).
Урок 27. Enum Struct в Amxx и их практическое применение на основе "Shop Menu"
Уроки по скриптингу для начинающих Здравствуйте, я увидел несколько реализаций Shop магазинов, и решил(тоже) поделиться своим подходом к этой задачи.
enum— — Перечисления. В основном используют в качестве "структуризации" данных.
Они позволяют: создать блок данных и установить разные значения в него. создавать свои константы с автоматическим инкрементом. создавать свои значения для переменных.
Урок 26. Какой редактор выбрать для написания плагинов для AMX Mod X?
Уроки по скриптингу для начинающих Начинающие скриптеры рано или поздно задают вопрос, какой редактор выбрать, какой из них лучше, в чем преимущества и недостатки того или иного продукта. После прочтения статьи у Вас появится информация по данным вопросам и Вы сможете самостоятельно сделать выбор.
Урок 25. Работа со словарями
Уроки по скриптингу для начинающих Данная статья предназначена для тех, кто хотел бы сделать свой сервер, либо отдельный плагин мультиязычным. Для этого существуют словари — файлы, содержащие в себе набор переменных, каждой из которых присвоено своё значение (слово или фраза на одном или нескольких языках). Эта статья как раз и посвящена словарям, точнее, работе с ними. Не будем углубляться в теорию, тем более, что, в данном случае, её почти и нет, разберём всё подробно на практике…
Урок 24. Позиция,скорость и углы в Half-Life (Position, Velocity, and Angles)
Уроки по скриптингу для начинающих Это руководство будет полезно новичкам с желанием узнать о Position(позиции), Velocity(скорости) и Anglesd(углах). Для того что бы понимать разницу в этих понятиях и успешно применять эти знания на практике.
Dimensions— — размерностиDimensions— — размеры, величина, объём, протяжение
0th dimension — нулевая размерность На картинке показана точка, которая не имеет ни какого размера. И у нас нет ни какой системы координат, что не позволит нам определить ее положение как на плоскости так и в пространстве.
Урок 23. Работа с сокетами (отправка email)
Уроки по скриптингу для начинающих В прошлом уроке мы с вами разобрали пример как получить web страницу с помощью сокетов.В этом уроке я расскажу о плагине Amx Mail v 0.1.0 от PomanoB`а. А точнее о функционале который он предоставляет, а именно набор функций:
smtp_connect— — Коннект к серверу smtpsmtp_auth— — авторизацияsmtp_send— — отправка письмаsmtp_quit— — закрытие соединения
Урок 22. Работа с сокетами (TCP http 80 порт)
Уроки по скриптингу для начинающих Данный урок предназначен для начинающих скриптеров, но уже знакомых с азами и некоторыми функциями такими как set_task, а так же знающие что такое сокеты. В уроке будет показан пример как работать с функциями которые предоставляет стандартный модуль sockets входящий в комплект amxmodx.
Урок 21. Отрезки времени без set_task на примере подсчета убийств за N секунд
Уроки по скриптингу для начинающих Не давно на одном форуме был задан вопрос о том как подсчитать количество фрагов за 5 секунд.Все предложенные варианты решения были с помощью функции set_task. Мне же было интересно сделать без ее использования, но автор темы поторопился ее закрыть. По этому решил что покажу пример тут. И так есть задача: Отловить количество чего либо ( в нашем варианте фрагов) за N (какое то) количество секунд. Отловить убийство игрока поможет функция RegisterHam с событием Ham_Killed, а дальше начинается сама логика процесса подсчета. 1 2 3 4
Урок 27. Enum Struct в Amxx и их практическое применение на основе "Shop Menu"
Урок 27. Enum Struct в Amxx и их практическое применение на основе "Shop Menu"
Уроки по скриптингу для начинающих Здравствуйте, я увидел несколько реализаций Shop магазинов, и решил(тоже) поделиться своим подходом к этой задачи.
enum— — Перечисления. В основном используют в качестве "структуризации" данных.
Они позволяют: создать блок данных и установить разные значения в него. создавать свои константы с автоматическим инкрементом. создавать свои значения для переменных. например: Довольно все знают bool значения… enum bool { false = 0, true Более подробное объяснение можно найти на оленях В самом низу темы будут приложены Исходники, которые мы здесь рассмотрим. На данный момент мы рассмотрим "Блок Данных". блок данных — в других языках семейства Си, С++ это структура данных(struct). Структура — некое объединение различных переменных, которых связывает что-то общее. Например: enum _:Игрок { Имя[32], Кол-во Жизней, Кол-во Брони
// этот список можно увеличивать и увеличивать, но мы остановимся на этом.
у нас теперь есть Общее понятие о Игроке мы его можем представить как Объект. Этот Объект можно использовать как обычную переменную, создать из неё массив т.д. Вот ещё один "маленький" пример структуры: Мы же все люди, верно?(знаю, есть коты которые сидят пока хозяев нет) представим структуру "Человек". enum _:Человек { Инициалы, возраст, Пол, Цвет Кожи, // и другие… дальше углубляться не буду, а то пойдёт наследование, полиморфизм… // это уже ближе к C++ 😀 И так. Давайте, перейдём к примерам. пример №1 (Примеры сделаны лишь для понимание работы с enum массивами, к примерам не будут прилагаться исходные коды, потому что написаны от руки в теме) enum _:Test_A { A_one, A_two[32]
new— Ab[Test_A];// так мы создали нашу "структуру"
// Использование:
public plugin_init() {
// Этот код написан лишь для примера.
пример №2 (создадим Массив на 100 элементов) enum _:Test_A { A_one, A_two[32]
new— Ab[100][Test_A];// так мы создали фиксированный массив наших "структур"
// Использование:
public plugin_init() {
// Этот код написан лишь для примера.
} пример №3 (Будем Использовать Array) enum _:Test_A { A_one, A_two[32]
new Array:Ab;
// Использование:
public plugin_init() {
Как и сказано в теме мы будем писать Shop Menu.
Мы напишем обычный Shop Menu с некоторыми уточнениями: При регистрации Item мы будем указывать имя функции CallBack. эта функция как раз и будет нашим обработчиком на выбор Item в меню, и функция будет должна вернуть какое-то значение Главному плагину для дальнейшей обработки. Меню не будет пересоздаватся для каждого отдельно(ну поверьте, это тупо постоянно листать циклом создавая одну и туже менюху ) Меню будет закрываться когда игрок Умер, или же кончился раунд (когда вы будете допиливать систему, или меня заставите, на разбитие команды, то это вам понадобится что бы TR не мог купить CT вещи или наоборот) Ну, последним моментом это будет Наиболее Оптимизация кода(если это потребуется) Если я не смогу проделать Оптимизацию в коде по причине что я не знаю, или ещё что-то… Я с удовольствием выслушаю, и приму меры(если потребуются). Начнём мы с *.inc файла. А назовём мы его : my_shop_menu.inc (Вы можете назвать по своему)
#include <cstrike>
#define SIZE 32
// Для начала подумаем что нужно для того что бы добавить новый предмет?
enum — _:MyMenuItem { ItemName[SIZE],// имя предмета ItemCost,// стоимость ItemForwardHandle// индекс форварда. }// Этот список можно увеличивать и увеличивать, но для примера этого хватит с головой// А теперь подумаем, если вдруг, Sub плагин которому отправили что пользователь выбрал
//этот Item. Он не хочет отрабатывать это, нам главному плагину это нужно как то знать...
//Вернуть какое-то значение от форварда (например, нет денег для покупки предмета).
enum — _:ShopReturns { Shop_OK = 1,// операция прошла успешно ShopNotEnoughMoney = 2,// нет денег на предмет Shop_False = 0/* натив регистрации */
native shop_register_item(item_name[SIZE], item_cost = 0, callback_function[SIZE] = "shop_buy_item");
// про значения по default, думаю, будет понятно, что если не указывать значение (указав знак _ ) то параметр будет присвоен тому что указано в прототипу функции.
/* можно ли купить предмет */
stock check_try_buy(id, iCost) {
new new_money = cs_get_user_money(id) — iCost; if(new_money < 0) return false; cs_set_user_money(id, new_money, 1); return true; У нас есть заготовка, теперь мы можем приступить к Главному Плагину.
#include <amxmodx>
#include <cstrike>
#include "my_shop_menu.inc"
new Array:ShopItems;
new HandleMenu = -1;
// звук который будет воспроизводится когда пользователь купил предмет
new const SoundBuy[] = "items/9mmclip1.wav";
public plugin_precache() precache_sound(SoundBuy);
public plugin_init() {
public— ShowShopMenu(id) {
if(is_user_alive(id)) menu_display(id, HandleMenu);
/* начало раунда */
public HLTV_New_Round() {
new iPlayers[32], z; get_players(iPlayers, z, "a"); for(new i; i < z; i++) CheckMenuClose(iPlayers[i]);
/* Смерть игрока */
public PlayerDeath() {
static id; id = read_data(2); if(!is_user_connected(id)) return; CheckMenuClose(id);
/* проверяем закрытое ли меню? если нет то закрывает */
CheckMenuClose(id) { new iCrap, iMenuId; player_menu_info(id, iCrap, iMenuId) if(iMenuId > -1 && (iMenuId == HandleMenu)) menu_cancel(id);
public— plugin_natives() {public— RegisterItem(iPlugin) {
register_native("shop_register_item", "RegisterItem");
new mDatas[MyMenuItem], szCallBack[SIZE]; get_string(3, szCallBack, charsmax(szCallBack)); mDatas[ItemForwardHandle] = CreateOneForward(iPlugin, szCallBack, FP_CELL); if((mDatas[ItemCost] = get_param(2)) > 0) { get_string(1, mDatas[ItemName], charsmax(mDatas[ItemName])) AddItemToMenu(mDatas); } return mDatas[ItemForwardHandle];
/* добавить в Shop Menu */
/* Handler CallBack главного меню. */
public ShopMenu_Handler(id, menu, item) {
if(item > MENU_MORE && is_user_alive(id)) { new mDatas[MyMenuItem]; ArrayGetArray(Array:ShopItems, item, mDatas); GetReturnForward(mDatas, id); }
/* Обработчик результатов от Sub плагинов */
GetReturnForward(mDatas[MyMenuItem], id) { new returned; ExecuteForward(mDatas[ItemForwardHandle], returned, id); switch(returned) { case Shop_OK: { emit_sound(id, CHAN_ITEM, SoundBuy, VOL_NORM, ATTN_NORM, 0, PITCH_NORM); return 1; } case ShopNotEnoughMoney: { client_print(id, print_center, "НЕТ ДЕНЕГ!"); } } return 0; и Так давайте рассмотрим этот код с более логической цепочки. Мы Создали
new— Array:ShopItems;
это и будет нашем хранилищем всех предметов в магази
Урок 23. Работа с сокетами (отправка email)
Урок 23. Работа с сокетами (отправка email)
Уроки по скриптингу для начинающих В прошлом уроке мы с вами разобрали пример как получить web страницу с помощью сокетов.В этом уроке я расскажу о плагине от PomanoB`а. А точнее о функционале который он предоставляет, а именно набор функций:
smtp_connect— — Коннект к серверу smtpsmtp_auth— — авторизацияsmtp_send— — отправка письмаsmtp_quit— — закрытие соединения
На самом деле, этот плагин ни что иное как прошлый урок, по результатам которого можно было бы написать собственный такой плагин, до Дядька Романыч позаботился о нас. По этому я расскажу только как применять эти функции, а тем кому интересно более детально узнать как работает плагин, сам изучит исходник. Который в конце данной статьи приложен. И так для работы нам потребуется: Плагин Amx Mail v 0.1.0 Инклуд amxmail ( в комплекте с плагином) Нами написанный мини пример Будем считать что все файлы находятся в нужных местах. Приступим к написанию примера, который будет отправлять на определенный электронный адрес письмо с определенным содержанием, ну скажем с именем сервера и текущей картой при его старте. Давайте подумаем как вы отправляете письмо другу? Скорее всего так:Заходите на страничку вашей почтовой системы или открываете программу клиент. ( то етсь соединяетесь с сервером) Далее вводится логин и пароль ( авторизация на сервере) Написание и отправка письма Закрытие странички или программы (закрытие соединения) Будущий плагин будет делать все тоже самое в той же самой последовательности. Не правда ли все просто? Начнем с коннекта к серверу:
/*
* Подключиться к SMTP серверу
* server - адрес сервера
* port - порт сервера
* В случае успеха функция вернёт идентификатор сервера,
* его надо использовать в первом параметре остальных функций
* В случае неудачи возвращает -1
*/
native smtp_connect(server[], port);
В описании функции и так все предельно понятно, но на всякий случай поясню что данные настройки вы можете посмотреть в справочных материалах ваших почтовых служб, вот пример Хелп mail.ru Из которого следует что адрес сервера smtp.mail.ru и нужный нам порт SMTP — 25, 587 или 2525 ( любой на выбор ) Далее следует авторизация:
/*
* Авторизация на SMTP сервере
* socket - идентификатор сервера
* username - имя пользователя (Например username@mail.ru)
* password - пароль
*/
native smtp_auth(socket, username[], password[]);
Обратите внимание, что первая функция возвращает идентификатор сокет соединения соединения, который будет первым аргументов функции. Логин и пароль указываются точно такими же как вы привыкли входить в свою почту. Наконец подошли к самой отправке письма:
/*
* Отправить письмо
* socket - идентификатор сервера
* from - от кого письмо (для большинства серверов должно совпадать с именем пользователя)
* to - кому письмо
* subject - тема письма
* mail - содержимое письма
* addHeaders - дополнительные заголовки (Например Reply-To:)
*/
native smtp_send(socket, from[], to[], subject[], mail[], addHeaders[]);
Функция не поддерживает форматирование, по этому передаваемые данные необходимо подготовить заранее, например с помощью функции format После успешной отправки ( а может и не отправки) необходимо закрыть открытое соединение с сервером:
/*
* Отключиться от сервера
* socket - идентификатор сервера
*/
native smtp_quit(socket);
Теоретически разобрались, посмотрим как это будет выглядеть в коде:
#include <amxmodx>
#include <amxmisc>
#include <amxmail>
#define PLUGIN "[ Send Mail" #define VERSION "1.0" #define AUTHOR "Admin"
public— plugin_init() {
register_plugin(PLUGIN, VERSION, AUTHOR) set_task(5.0,"send",0)
public send(){
//Подготавливаем текст для письма new text[1024],MapName[32],ServerName[32] get_user_name(0,ServerName,31) get_mapname(MapName,31) format(text,charsmax(text),"Hello Admin! From server:%s , map in server [%s]",ServerName,MapName) new connect // Создаем переменную для хранения идентификатора соединения connect = smtp_connect("smtp.mail.ru",587)//Соедиенние и получение идентификатора if(connect != -1){// Проверяем что соединение установлено smtp_auth(connect,"login","pass")// Авторизация smtp_send(connect,"TVOI@mail.ru","KOMY@list.ru","TeMa: Server start",text,"To:")//Отправка письма smtp_quit(connect)//Закрытие соединения }else{ server_print("ERROR Connect to SMTP") } Вот тут: "TVOI@mail.ru","KOMY@list.ru" Можете ввести свой почтовый адрес в двух местах, и тогда получится что вы пришлете письмо самому себе. Надеюсь теперь вы понимаете как использовать данный плагин. Ах да, функция set_task там необходимо для того, что бы плагин amx_mail точно успел загрузиться. ( мало ли он у вас ниже в списке плагинов окажется) Теперь исходный код плагина amx_mail: Показать / Скрыть текст
/* Plugin generated by AMXX-Studio */
#include <amxmodx>
#include <sockets>
#include <amxmail>
#define PLUGIN "Amx Mail" #define VERSION "0.1.0" #define AUTHOR "PomanoB" #define MAX_CONNECTIONS 3 #define MAIL_TIMEOUT 10.0 #define MAIL_DEBUG enum mailStatus mail_status_send, mail_status_quit
new— g_sockets[MAX_CONNECTIONS]new— mailStatus:g_status[MAX_CONNECTIONS]new— Array:g_mailData[MAX_CONNECTIONS]public— plugin_init()public— plugin_natives()public— _smtp_connect(plugin, params)public— _smtp_auth(plugin, params)public— _smtp_send(plugin, params)public— _smtp_quit(plugin, params)public— base64encode(str[], outStr[])
register_plugin(PLUGIN, VERSION, AUTHOR) set_task(1.0, "recvTask", _, _, _, "b") new i for (i = 0; i < MAX_CONNECTIONS; i++) g_mailData[i] = ArrayCreate(512, 32)
register_library("amxmail") register_native("smtp_connect","_smtp_connect"); register_native("smtp_auth","_smtp_auth"); register_native("smtp_send","_smtp_send"); register_native("smtp_quit","_smtp_quit");
new i, error, server[32] for (i = 0; i < MAX_CONNECTIONS; i ++) { if (!g_sockets[i]) break } if (i == MAX_CONNECTIONS) return -1 get_string(1, server, charsmax(server)) server_print("[%s][%d]",server,get_param(2)) g_sockets[i] = socket_open(server, get_param(2), SOCKET_TCP, error) if (error) { server_print("[%s]",error) g_sockets[i] = 0 return -1 } return i
new socket, username[64], password[64], data[512] socket = get_param(1) get_string(2, username, charsmax(username)) get_string(3, password, charsmax(password)) ArrayPushString(g_mailData[socket], "EHLO AmxMailer^r^n") ArrayPushString(g_mailData[socket], "AUTH LOGIN^r^n") base64encode(username, data) add(data, charsmax(data), "^r^n") ArrayPushString(g_mailData[socket], data) base64encode(password, data) add(data, charsmax(data), "^r^n") ArrayPushString(g_mailData[socket], data) g_status[socket] = mail_status_send return 0
new socket, from[64], to[64], subject[64], mail[512], addHeaders[64], data[512] socket = get_param(1) get_string(2, from, charsmax(from)) get_string(3, to, charsmax(to)) get_string(4, subject, charsmax(subject)) get_string(5, mail, charsmax(mail)) get_string(6, addHeaders, charsmax(addHeaders)) formatex(data, charsmax(data), "MAIL FROM: %s^r^n", from) ArrayPushString(g_mailData[socket], data) formatex(data, charsmax(data), "RCPT TO: %s^r^n", to) ArrayPushString(g_mailData[socket], data) formatex(data, charsmax(data), "DATA^r^n") ArrayPushString(g_mailData[socket], data) formatex(data, charsmax(data), "To: %s^r^nFrom: %s^r^nSubject: %s^r^n", to, from, subject) if (strlen(addHeaders)) add(data, charsmax(data), addHeaders) format(data, charsmax(data), "%s^r^n%s^r^n.^r^n", data, mail) ArrayPushString(g_mailData[socket], data)
ArrayPushString(g_mailData[get_param(1)], "QUIT^r^n")
static const base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" new index1, index2, byte, mul, ch, out new len len = strlen(str) while (len—) { byte = str[ch++] index1 = index2|((byte>>(1+mul)*2)&0x3F) index2 = (byte<<(2 — mul)*2)&0x3F outStr[out++] = base64[index1] if (mul++ == 2) { outStr[out++] = base64[index2] mul = index2 = 0 } } if (mul != 0) { outStr[out++] = base64[index2] while (3 — mul++) outStr[out++] = '=' } outStr[out] = 0
public recvTask()
static i, socket, data[512], replyCode static Float:la
Урок 22. Работа с сокетами (TCP http 80 порт)
Урок 22. Работа с сокетами (TCP http 80 порт)
Уроки по скриптингу для начинающих
Модуль дает возможность использовать как TCP так и UDP соединение:
// Use SOCKET_TCP for TCP Socket connections
#define SOCKET_TCP 1
// Use SOCKET_UDP for UDP Socket connections
#define SOCKET_UDP 2 Какая разница между ними?
TCP— — расшифровывается как Transmission Control Protocol и осуществляет полную и правильную передачу данных между конечными устройствами, но единственная проблема это то, что если данные между конечными устройствами будут повреждены то будет повторена передача. В связи с этим этот протокол иногда может быть более медленным.UDP— — означает User Datagram Protocol и не имеет контроля целостности данных. В связи с этим быстрее.socket_open— — открывает новое соединение к удаленному серверуsocket_close— — закрывает соединениеsocket_recv— — получает данные в строкуsocket_send— — отправляет данные в сокет/запросsocket_send2— — отправляет данные в сокет/запрос с возможностью содержания нулевых байтовsocket_change— — возвращает истину если в ответе сокета были изменения в течении заданного таймаута
Более подробную информацию можно получить в поиске 😉 Функции:
//Наши данные
//Константы для функций set_task
g_Socket— = socket_open(PLUGIN_HOST, 80, SOCKET_TCP, error)g_Socket— Заранее созданная глобальная переменная, в которую будет записан идентификатор открытого соединения.sendbuffer— — массив куда запишется сформированная запросGET— — Это тип запроса ( для веб серверов есть GET и POST запросы, читайте об этом на соответствующих ресурсах или тут.)(GET — запрос в одну строку, POST — передача блока данных)GET— /list.html HTTP/1.1socket_change— ( g_Socket )socket_recv— ( g_Socket , g_Data , 999 )g_Socket— Идентифигактор сокетаg_Data— Массив для данныхml— xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru" lang="ru">
Далее все понятно: Хост, порт, тип протокола и переменная для записи ошибки (значение отличное от 0), если таковая возникнет и если необходимо знать что случилось пишем следующее: switch (error) { case 1: { //Не возможно создать сокет log_amx("[ Unable to create socket.") return } case 2: { //Невозможно подключиться к хосту log_amx("[ Unable to connect to hostname.") return } case 3: { //Невозможно подключиться к указанному порту log_amx("[ Unable to connect to the HTTP port.") return } } Если соединение прошло успешно, то сформируем и передадим запрос к серверу: //Массив для запроса new sendbuffer[512] //Формирование запроса format(sendbuffer, 511, "GET %s HTTP/1.1^nHost:%s^r^n^r^n", PLUGIN_TOPIC, PLUGIN_HOST) //Отсылка запроса socket_send(g_Socket, sendbuffer, 511) Тут хочется отдельно прокомментировать сам запрос: format(sendbuffer, 511, "GET %s HTTP/1.1^nHost:%s^r^n^r^n", PLUGIN_TOPIC, PLUGIN_HOST)
511 — его длина
HTTP/1.1 b ^nHost: тоже относится к синтаксису GET запроса
Host: www.example.org То есть если вы будите использовать какой другой порт, например порт сервера для получения данных о игроках, то запрос будет совсем другой, и эту информацию можно получить и в справочных материалах сервера или документации компании разработчика или в других источниках. Для CS серверов можно посмотреть тут: Server_Queries Goldsource_servers_2 Далее мы должны использовать set_task функции для того, чтобы ждать ответа от сервера. Это необходимо так как сетевой трафик может быть огромным, и ответ сервера может занять некоторое время. Нам просто нужно убедиться, что больше данных не будет получено. Именно поэтому будут использованы 2 задачи. Одна для получения ответа сервера, а другая для закрытия соединения. / / Мы повторяем первую задачу 15 раз, чтобы проверить, 15 раз каждую секунду, если мы получим ответ и чтобы убедиться, что информация, которую мы хотим искать это в том, что ответом. //Данная задача будет выполнена 15 раз, что бы проверить каждый раз не получена ли еще информация от сервера, // как только информация будет такой же как и в прошлом ответе, будет выполнена вторая задача set_task ( 1,0 , "task_waitanswer" , TASKID_GETANSWER , "" , 0 , "а" , 15 ) / / Вторая задача закрывает подключение, если в первой задаче ничего не было сделано. set_task ( 16,0 , "task_closeconnection" , TASKID_CLOSECONNECTION , "" , 0 , "" , 0 ) Теперь переходим к функции которая будет получать и проверять ответы от сервера: С самого начала необходимо проверить были ли изменения в в ответе сервера.
И если это так, то мы должны получить данные из него и посмотреть, если буфер уже имеет метатег description и версию урока что ыб была достигнута наша цель.
999Длина массива Если вывести содержимое массива с данными — то вы получите вот что: HTTP/1.1 200 OK Date: Wed, 26 Dec 2012 21:04:22 GMT Server: Apache/2.2.22 (Win32) PHP/5.2.3 X-Powered-By: PHP/5.2.3 Set-Cookie: PHPSESSID=cd67e50sdafasdfafs2950edfface2b727; path=/ Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-ca
<head> <meta http-equiv="Content-Type" content="text/html; charset=windows-1251" /> <title>╙Ёюъ її ╨рсюЄр ё ёюъхЄрьш » AmxModX ╤ъЁшяЄшэу фы эютшўъют т яЁшьхЁрї</title> <meta name="description" content=" Это ответ сервера, и если дать время, то в этот ответ будет загружена вся данная статья, но мы ищем определенный html тег в начале страницы. Который уже есть в ответе, мы это проверим и остановим дальнейшее выполнение заданий, так как остальные данные со страницы нам не нужны, а т
Урок 20. Что такое Stocks
Урок 20. Что такое Stocks
Уроки по скриптингу для начинающих У новичков регулярно возникает вопрос чем отличаются stock функции от native, давайте разберемся вместе.
Stock— функция (в основном, так как может быть и переменной) которая если не используется где-нибудь в плагине, будет попросту проигнорировна компилятором. То есть компилятор как бы не заметит ее вовсе.
Многим новичками приходит идея сделать так:
#include <amxmodx>
#include <amxmisc>
public plugin_init()
register_plugin("The","Matrix","Has You") fnDoFunc()
stock fnDoFunc()
log_amx("the world has imploded upon itself") Хотя фактически та же самая функциональность могла быть достигнута так:
#include <amxmodx>
#include <amxmisc>
public plugin_init()
register_plugin("The","Matrix","Has You") fnDoFunc() fnDoFunc() log_amx("the world has imploded upon itself") Но для чего тогда нужны эти сток функции? В основном там, где есть инклюды с множеством функций, из которых обычно используется малая часть. Например возьмем инклюд engine_stocks.inc от модуля engine. Начало файла:
stock— fakedamage(idvictim,const szClassname[],Float:takedmgdamage,damagetype)
new entity = create_entity("trigger_hurt"); if (entity) { DispatchKeyValue(entity,"classname","trigger_hurt"); new szDamage[16]; // Takedamages only do half damage per attack (damage is damage per second, and it's triggered in 0.5 second intervals). // Compensate for that. format(szDamage,15,"%f",takedmgdamage * 2); DispatchKeyValue(entity,"dmg",szDamage); format(szDamage,15,"%i",damagetype); DispatchKeyValue(entity,"damagetype",szDamage); DispatchKeyValue(entity,"origin","8192 8192 8192"); DispatchSpawn(entity); entity_set_string(entity, EV_SZ_classname, szClassname); fake_touch(entity,idvictim); remove_entity(entity); return 1; } return 0;
//wrapper for find_ent_by_class
stock find_ent(iStart, const szClassname[])
return find_ent_by_class(iStart, szClassname);
//...
Если в плагине будет использована функция find_ent, то она будет включена в скрипт. А функцию stock fakedamage в плагин не использовалась в плагине и она не будет включена в скрипт.
Stock— может быть и переменной:stock— const mystring[] = "hello pm"
Лично я не имел с ними дело, по этому опущу это, если интересно — переведите сами. Вот ссылка оригинальный материал: [TUT] The Use of Stocks
Урок 20. Что такое Stocks
Выброс оружия (stock)
md5— — вычисляет MD5 хеш строкиget_configsdir— Функция получает путь к папке с конфигами сервера
Урок 4. Какие бывают функции. Типы функций.
is_map_valid— Функция проверяет есть ли карта на сервере
Урок 19. Отличие new от static при создании переменных. В чем разница New и Static
Урок 19. Отличие new от static при создании переменных.
Уроки по скриптингу для начинающих Тем кто знает отличие new от static читать данный урок нет необходимости, нового вы ни чего не узнаете. А тем кто не понимал в чем отличие, наверное будет полезно прочитать данную статью. Оба рассматриваемых оператора создают переменную, но у них существует определенная разница. Оператор NEW Для начала давайте рассмотрим оператор new на примере вот такой функции:
public— func_new(){// Какая то функцияcmd_new— — Это команда вызывающая функцию func_new.public— func_static(){//Другая функцияStatic— — рекомендуется использовать там, где происходит очень частое использование.
new i // создание переменной server_print("i=%d",i) // вывод значения переменной i++ // прибавляем 1 к переменной server_print("i+1 i=%d",i)//выводим переменную с +1 Если вызвать данную функцию два раза подряд, то результат будет такой: cmd_new i=0 i+1 i=1 cmd_new i=0 i+1 i=1
Как видно результат одинаковый, это потому что оператор new создает переменную в памяти каждый раз при объявлении, то есть старая была уничтожена. Оператор Static Если в данном коде заменить оператор new на static то получится вот такой код:
static i// заменили new на static server_print("i=%d",i) i++ server_print("i+1 i=%d",i) И результат работы уже будет такой: cmd_static i=0 i+1 i=1 cmd_static i=1 i+1 i=2 Как видно из результата — переменная сохранила свое значение, так как оператор static не пересоздает переменную, а продолжает работать с ране созданной. Логично предположить что многие сразу скажут — " Так это же обычная глобальная переменная", но это не так, глобальная переменная доступна везде, а переменная созданная с помощью static внутри какой то функции, будет доступна только там.
Рабочий пример:
#include <amxm
Урок 18. Вызов функции в определенный час дня.(Определенное время).
Урок 18. Вызов функции в определенный час дня.
Уроки по скриптингу для начинающих Несколько раз я натыкался на вопросы вроде:
Как сделать так чтоб, определённая функция работала в определённое время?Например каждый день в 00.00
Обычно я проходил мимо данного вопроса, а тот что то меня зацепило и я решил попробовать реализовать первый пришедший в голову алгоритм. При загрузке плагина выполнять следующие действия: Получить время на сервере в требуемом формате ( часы, минуты секунды ) Определить разницу между текущим временем и тем когда необходимо выполнить функцию. С помощью функции set_task задать задание с полученным ранее временем Вот что у меня из этого вышло:
/* Plugin generated by AMXX-Studio */
#include <amxmodx>
#include <amxmisc>
#define PLUGIN "[ Function call in exact time" #define VERSION "1.0" #define AUTHOR "Admin"
public— plugin_init() {
register_plugin(PLUGIN, VERSION, AUTHOR) server_print("^n^n^n^n^n") new hour,minute,secound //Задаем час и минуты для задания new Fhour = 1,Fminute = 11 //Получение текущего времени time(hour,minute,secound) //Для наглядности вывод в консоль сервера server_print("The Time: %dh. %dm. %ds.",hour,minute,secound) //Сколько времени в секундах ( относительно суток ) new RealTimeSec = (hour*60*60)+(minute*60)+ secound //Вычесляем сколько времени нужно до заданного new TimeToStartFunc = (Fhour*60*60)+(Fminute*60) — RealTimeSec //Вывод текущего времени и во сколько должна сработать функция server_print("Time[%d:%d] — FStart[%d:%d], Time to start[%d]",hour,minute,Fhour,Fminute,TimeToStartFunc) //Если время для задания положительное if(TimeToStartFunc > 0){ //Преобразование целого числа в дробное ( необходимо для set_task) new Float:sec = float(TimeToStartFunc) //Задаем задание с необходимым времем set_task(sec,"func",777) }else{ server_print("Time passed") } server_print("^n^n^n^n^n")
public func(){
server_print("^n^n^n^
Урок 16. Работа с Двумерным и Трехмерным массивами
Урок 16. Работа с Двумерным и Трехмерным массивами
Уроки по скриптингу для начинающих Многомерные массивы довольно часто используется в больших работах и бывают просто необходимы. Больше трехмерного на сколько я знаю не существует. Двумерный массив не сильно отличается от простого. В каждой ячейки простого массива 1 место для записи числа, символа. Так Двумерный массив дает в 1 ячейке больше места, то есть больше одного это уже зависит от того сколько вы укажите. Покажу на картинке так как думаю меня не все поняли. Я создал двумерный массив с тремя ячейками в трех.
Как видите массив преобразовался в каждую ячейку добавились еще три.
Вот как это выглядит в коде.
new— iMassive[3][3] =
{1, 2, 3}, //iMassive[0] {4, 5, 6}, //iMassive[1] {7, 8, 9} //iMassive[2]
};
Расскажу про трехмерный массив. Он повторяет такие же действия что и двумерный. То есть в двумерном мы ставили в каждую ячейку еще три, а в трехмерном будет 2 ячейки в каждой по 2 и еще в которых по 2 еще 2. Рассмотрим на картинке, у кого хорошо развито логическое мышление поймет, хотя мне и то было сложновато. Видим трехмерный массив. В 2 ячейки добавили еще 2 и в 2 добавленные еще по 2. Вот как это выглядит в коде.
new— iMasive[2][2][2] =
{ { 1, 2 }, { 3, 4 } }, { { 5, 6 }, { 7, 8 } }
};
//или
new Massive[2][2][2] =
{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}
};
На этом теория законченна, перейдем к примерам: Двумерный массив:
/* Plugin generated by AMXX-Studio */
#include <amxmodx>
#include <amxmisc>
#define PLUGIN "New Plug-In" #define VERSION "0.1" #define AUTHOR "Mon[str]"
enum— _:INFO_SCORE
FRAGS = 0, DEATHS //1
};
//Объявим двумерный массив с размеом 33, 2
new g_iInfo[33][INFO_SCORE];
public plugin_init()
register_plugin(PLUGIN, VERSION, AUTHOR); //Зарегистрируем евент смерти register_event("DeathMsg", "Event_DeathMessage", "a"); //Зарегистрируем команду для показа нашей информации register_clcmd("say /score", "score");
public— client_connect(id)public— Event_DeathMessage()public— client_disconnect(id)
//Обнуляем при коннекте g_iInfo[id][FRAGS] = 0; g_iInfo[id][DEATHS] = 0
new iKiller = read_data(1); new iVictim = read_data(2); //Плюсуем фраги убившему g_iInfo[iKiller][FRAGS]++; //Плюсуем смерти погибшему g_iInfo[iVictim][DEATHS]++;
//Обнуляем при дисконнекте g_iInfo[id][FRAGS] = 0; g_iInfo[id][DEATHS] = 0
public score(id)
//Выводим client_print(id, print_chat, "Your Frags: %d, Your Deaths: %d", g_iInfo[id][FRAGS], g_iInfo[id][DEATHS]) //Блокируем команду в чат return 1; Этот код будет считать ваши смерти и убийства и выводить при желании. Грубо говоря для каждого игрока по 2 ячейки это убийства и смерти. Трехмерный:
/* Plugin generated by AMXX-Studio */
#include <amxmodx>
#include <amxmisc>
#define PLUGIN "New Plug-In" #define VERSION "0.1" #define AUTHOR "Mon[str]" #define IS_HEDSHORT 0 #define IS_SUICIDE 0 #define NORM 1 enum _:SCORE FRAGS = 0, DEATHS //1
};
//Объявим трехмерный массив с размеом 33, 2, 2
new g_iInfo[33][SCORE][2];
public plugin_init()
register_plugin(PLUGIN, VERSION, AUTHOR); //Зарегистрируем евент смерти register_event("DeathMsg", "Event_DeathMessage", "a"); //Зарегистрируем команду для показа нашей информации register_clcmd("say /score", "score");
public— client_connect(id)public— Event_DeathMessage()
//Обнуляем при коннекте g_iInfo[id][FRAGS][IS_HEDSHORT] = 0; g_iInfo[id][FRAGS][NORM] = 0; g_iInfo[id][DEATHS][IS_SUICIDE] = 0; g_iInfo[id][DEATHS][NORM] = 0;
new iKiller = read_data(1); new iVictim = read_data(2);
Урок 15. Создание собственной multi forward функции и работа с ней в других плагинах.
Урок 15. Создание собственной multi forward функции и работа с ней в других плагинах.
Уроки по скриптингу для начинающих Цель данного урока научить вас создавать свою forward функцию, то есть функцию, которая вызывается не по требованию, а всегда при наступлении какого то события, при этом эту функцию можно будет использовать в любом другом плагине. Простым примером может послужить Зомби мод, где большая часть игровых событий имеют подобные функции, что дает возможность писать небольшие дополнения вне самого мода. Вот например функция:
/**
* Called when a player becomes the last zombie.
* Note: This is called for the first zombie too.
* @param id Player index.
*/
forward zp_user_last_zombie(id) Она вызывается каждый раз когда остается последний зомби и передает его айди. Другие функции можно посмотреть в соответствующих плагину файлах в папке include и с расширением inc. Надеюсь, вы поняли о чем речь и можно переходить к конкретной практике.
Для создания forward функции необходимо знать две функции: CreateMultiForward ExecuteForward Изучили? Замечательно, поехали дальше. Это будет первый плагин(основной):
/* Plugin generated by AMXX-Studio */
#include <amxmodx>
#include <amxmisc>
#define PLUGIN "[amxmodx.inc] ExecuteForward" #define VERSION "1.0" #define AUTHOR "Admin"
new g_fwd_first
public plugin_init() {
register_plugin(PLUGIN, VERSION, AUTHOR) g_fwd_first = CreateMultiForward("my_first_multi_forward", ET_CONTINUE, FP_CELL,FP_CELL) server_print("Forward[%d]",g_fwd_first)
public— client_connect(id){
new num = 5 new ret ExecuteForward(g_fwd_first,ret,id,num) //Результат будет 98 (далее вы поймете почему) //Второго плагина с функцией my_first_multi_forward server_print("ret[%d]",ret) Далее необходимо создать файл который будет рассказывать другим плагинам что за функцию волшебную мы придумали и назовем его new_forwards.inc, не забыли в какую папку его необходимо сохранить? Вижу, правильно думаете в папку include. После чего в него помещаем информацию о нашей функции:
/*
* Тестовая функция, вызывается каждый раз
* Когда заходит игрок
* Параметры:
* id - айди игрока
* num - какое то число
*/
forward my_first_multi_forward(id,num)Разумеется данный пример не имеет ни какого смысла, так как создаваемый форвард дублирует уже существующий client_connect, но сейчас наша задача научиться работать с форвардами, а не придумывать их.
Далее необходим второй плагин, где бы использовалась данная функция:
/* Plugin generated by AMXX-Studio */
#include <amxmodx>
#include <amxmisc>
//Подключение библиотеки, которая расскажет скрипту о функции
#include <new_forwards>
#define PLUGIN "[amxmodx.in
Урок 13. Включение и выключение функции игроком.
Урок 13. Включение и выключение функции игроком.
Уроки по скриптингу для начинающих
Как сделать включение и выключение функции по команде для каждого игрока.
Какая же логика у данного процесса? Для начала нужно определиться будет ли нужная функция при подключении к серверу включена или выключена. Для примера представим, что функция для игрока будет по умолчанию выключена:
new— bool:g_bFuncUse [33] = false
В данном коде создается массив из булевых переменных присваивается значение ложь всем массиву. Этот массив и является «переключателем» выключена/выключена функция для каждого из игроков по отдельности. Но как вы уже догадались, сам по себе выключатель ни чего не сделает, его нужно включить в какую то схему, этой схемой будет «Условие» в котором будет проверяться положение «переключателя»:
if(g_bFuncUse[id]){
//Выключатель включен }else{ //Выключатель выключен Вроде бы как все работает, но чего то не хватает не так ли? Вижу, правильно думаете! Не хватает команды которая будет включать и выключать переключатель. С этим еще проще, регистрируем команду say и создаем для нее функцию:
register_clcmd("say","fOnOff")
…
public fOnOff(id){
//Получение что написал игрок new args[10] read_args(args,9) remove_quotes(args) //Если было написано /off if(equal(args, "/off", 4)){ g_bFuncUse[id] = false client_print(id,print_chat,"[scripts] Cmd disable") } //Если было написано /on if(equal(args, "/on", 4)){ g_bFuncUse[id] = true client_print(id,print_chat,"[scripts] Cmd is activated") }
Как вы уже догадались, команды у нас будут say /on и say /off.
А так же нельзя забывать, что игрок может выйти и на его место войдет другой, по этому переменную нужно приводить в исходное состояние, например так:
public— client_connect(id){
g_bFuncUse[id] = false Можно и при выходе игрока, в теории разницы ни какой нету, все зависит от структуры вашего плагина. Теперь осталось только сделать какую то наглядную функцию, при включении/выключении которой сразу же будет что то происходить. Например можно поиграться с гравитацией, так как там значение изменяется всего одной функцией и не повторятся, то можно изменить ее значение прямо где изменяли положение переключателя, но все же хочется привести пример с использованием переключателя в другой функции, для этого возьмем пример плагина бесконечных патронов, добавим в него наши наработки и получим вот что:
/* Plugin generated by AMXX-Studio */
#include <amxmodx>
#include <amxmisc>
#include <fun>
#include <fakemeta>
#include <hamsandwich>
new const MAXBPAMMO[] = { -1, 52, -1, 90, 1, 32, 1, 100, 90, 1, 120, 100, 100, 90, 90, 90, 100, 120,
30, 120, 200, 32, 90, 120, 90, 2, 35, 90, 90, -1, 100 }
new— const MAXCLIP[] = { -1, 13, -1, 10, -1, 7, -1, 30, 30, -1, 30, 20, 25, 30, 35, 25, 12, 20,new— bool:g_bFuncUse[33] = falsepublic— plugin_init()
10, 30, 100, 8, 30, 30, 20, -1, 7, 30, 30, -1, 50 } #define PLUGIN "[scripts] on/off function" #define VERSION "1.0" #define AUTHOR "Admin"
register_plugin(PLUGIN, VERSION, AUTHOR) register_clcmd("say","fOnOff") register_message(get_user_msgid("CurWeapon"), "messageCurWeapon")
public fOnOff(id){
new args[10] read_args(args,9) remove_quotes(args) if(equal(args, "/off", 4)){ g_bFuncUse[id] = false client_print(id,print_chat,"[scripts] Cmd disable") set_user_gravity(id,1.0) } if(equal(args, "/on", 4)){ g_bFuncUse[id] = true client_print(id,print_chat,"[scripts] Cmd is activated") set_user_gravity(id,0.5) }
public— client_connect(id){public— messageCurWeapon(msg_id, msg_dest, msg_entity){
g_bFuncUse[id] = false
if(!g_bFuncUse[msg_entity]) return PLUGIN_CONTINUE if(get_msg_arg_int(1) != 1) return PLUGIN_CONTINUE static weapon weapon = get_msg_arg_int(2) if(MAXBPAMMO[weapon] > 2){ set_pdata_int(get_pdata_cbase(msg_entity, 373), 51, MAXCLIP[weapon], 4) set_msg_arg_int(3, get_msg_argtype(3), MAXCLIP[weapon]) } return PLUGIN_CONTINUE } Но в функции messageCurWeapon, использован немного другой способ контроля положения переключателя выл/выкл. Раньше у нас была логика такая: Если переключатель включен то: … Если нет то … А в данном варианте: if(!g_bFuncUse[msg_entity]) return PLUGIN_CONTINUE Если переключатель не включен, то возвращаем return PLUGIN_CONTINUE, что прервет дальн
Урок 11. Кнопочные константы (Amx Mod X) или как поймать нажатие кнопки.
Урок 11. Кнопочные константы (Amx Mod X) или как поймать нажатие кнопки.
Уроки по скриптингу для начинающих Кнопочные константы используются для того, чтобы отловить момент, когда игровой объект совершает какое то действие, такое как прыжок, атака или передвижение. Этот метод используется из-за того, что движок HL не может «отловить» команды которые имеют противоположные знаки, такие как +jump/-jump Этот пример работать будет:
register_concmd("+explode","explode")
А вот команда attack имеет +/- состояние и работать не будет.
register_concmd("+attack","hook_attack")
Полный список всех констант: #define IN_ATTACK (1<<0) #define IN_JUMP (1<<1) #define IN_DUCK (1<<2) #define IN_FORWARD (1<<3) #define IN_BACK (1<<4) #define IN_USE (1<<5) #define IN_CANCEL (1<<6) #define IN_LEFT (1<<7) #define IN_RIGHT (1<<8) #define IN_MOVELEFT (1<<9) #define IN_MOVERIGHT (1<<10) #define IN_ATTACK2 (1<<11) #define IN_RUN (1<<12) #define IN_RELOAD (1<<13) #define IN_ALT1 (1<<14) #define IN_SCORE (1<<15)
Как же все таки поймать момент нажатия кнопки игроком?
Вот рабочий вариант отлова момента когда игрок нажимает кнопку атаки:
#include <amxmodx>
#include <engine>
public plugin_init(){
register_plugin("Attack Test","1.0","Hawk552")
public— client_PreThink(id){
if(entity_get_int(id,EV_INT_button) & IN_ATTACK) { client_print(id,print_chat,"You in attack") } Обращаю ваше внимание, что используется оператор & , основное отличие оператора && от & заключается в том, что оператор & проверяет, есть ли бит после оператора в предыдущем бите до него. То есть в данном случае идет проверка, есть ли нужная нам кнопка, среди множества нажатых одновременно других клавиш. Если вам необходимо заставить нажать игрока кнопку, можно воспользоваться данным методом:
#include <amxmodx>
#include <engine>
public plugin_init() {
register_plugin("Attack Test","1.0","Hawk552")
public— client_PreThink(id) {
entity_set_int(id,EV_INT_button,IN_ATTACK) Приведенный код, будет зажимать за игрока кнопку атаки. (Для наглядности выберите нож) Обратите внимание на то, что эмулируется именно атака, а не нажатие кнопки мышки, так как ее забиндить можно куда угодно.
#include <amxmodx>
#include <engine>
public plugin_init(){
register_plugin("Attack Test","1.0","Hawk552")
public— client_PreThink(id) {
entity_set_int(id,EV_INT_button,entity_get_int(id,EV_INT_button) & ~IN_ATTACK) Если игрок прыгает IN_JUMP и атакует IN_ATTACK в один и тот же момент,то функция entity_get_int(id,EV_INT_button) будет возвращать значения IN_ATTACK и IN_JUMP. С помощью оператора ~ будет удаляться указанное значение бита, в нашем случае IN_ATTACK. Для наглядности выберите нож и зажмите кнопку атаки во время прыжка или других действий, "все будет хорошо", кроме прерывающейся атаки. Первоисточник: Button_constants (AMX_Mod_X) Маленький бонус от меня: Забавный момент:
#include <amxmodx>
#include <en
Урок 7. Что такое алгоритм и как его составить.
Урок 7. Что такое алгоритм и как его составить.
Уроки по скриптингу для начинающих Алгоритм — это точный набор инструкций (функций),описывающий порядок действий плагина для достижения результата решения задачи ( цели плагина). Это немного урезанное определение специально для плагинов ;)) На самом деле мы каждый свой день проживаем с помощью циклов и алгоритмов, просто не задумываясь об этом. Кто из вас задумывался как он ходит в школу или на работу? Пожалуй ни кто, ни кто не задумывался о том, что бы просто дойти до школы он выполняет целую кучу действий:( проснулся, умылся, собрался) вышел из квартиры закрыл квартиру ( я уже молчу о достать ключи, выбрать нужный ключ, вставить в замочную скважину, подумать в какую сторону закрывается замок и так далее) вызвал лифт подождал лифт зашел в лифт и так далее, , целые тысячи мелкий, но для нас простых операций. Которые происходят каждый раз в одной и той же последовательности, совсем немного изменяясь, но в целом остается все одинаково в общих чертах. В плагине же происходит точно так же, плагину нужен точный, пошаговый, алгоритм действий, что бы выполнить поставленную задачу.То есть если вы хотите дать игроку при старте раунда какое то оружие, то необходимо построить логическую цепочку ( алгоритм) как будет этот плагин работать: Если давать оружие при событии старта раунда, то нужно его отловить отловили ( есть разные способы,решать вам каким пользоваться) Далее нам необходимо выбрать кому именно (допустим админу) выдать оружие. С помощью цикла вычисляем админов. Даем им оружие. Зачастую проблема в редактировании плагина заключается не в том, что человек не знает как дать еще жизней игроку, а в том что не знает в каком месте это нужно сделать, ведь на вопрос как добавить hp на любом форуме дадут ответ через 10 секунд. Если же человек сначала пропишет на бумажке (именно на бумаге лучше составлять алгоритм, там легче рисовать стрелочки что с чем взаимосвязано) и потом в коде плагина по
Урок 6. Циклы. Какие бывают циклы. (Что такое for,while,do while)
Урок 6. Циклы. Какие бывают циклы. (Что такое for,while,do while)
Уроки по скриптингу для начинающих Если по простому, то это регулярно повторяющиеся события. Например Недельный цикл. В каждой недели 7 дней которые повторяются из недели в неделю. В PAWN`e практически все тоже самое, главное разобраться как работает каждый из циклов. Цикл — это выполнение одного и того же кода определенное количество раз. Зачем нужны циклы. Они необходимы когда появляется Необходимость выполнить функцию для каждого игрока непосредственно в данный момент. Выполнить какой то код необходимое количество раз — например составление топ 15 (он же составляется построчно). Какие бывают циклы. В Pawn циклы бывают трех видов:
For— — Цикл со счетчиком. Необходимо использовать когда мы знаем количество итераций цикла ( итерация — повторное выполнение функции)While— — Цикл с предусловием. Будет выполняться пока условие верноdo— while — Цикл с постусловием. Будет выполниться первый раз и проверит условие и если оно верно выполниться снова и так дока условие будет верно
Синтаксис и примеры циклов.
Синтаксис цикла for следующий for(оператор_инициализация; условие; поститерационная_команда ) Х //Тело цикла } Как он работает: Перед первой итерацией ( проходом ) выполняется оператор инициализации, обычно это инициализация счетчика цикла. Затем проверка условия, и если оно истинно ( к пример 1=1), то выполняется тело цикла, а после того как оно выполнено — поститерационная команда. Вот как это работает наглядно: for( new i = 1; i <= 10; i++) { server_print("For: %d",i) } new i = 1 — объявили новую переменную и сказали что она равно единице
Урок 5. Тернарная условная операция ( аналог if-else )
Урок 5. Тернарная условная операция ( аналог if-else )
Уроки по скриптингу для начинающих Тернарная условная операция (обычно записывается как ?:) — во многих языках программирования операция, возвращающая свой второй или третий операнд в зависимости от значения логического выражения, заданного первым операндом. Обычно тернарная условная операция ассоциируется с операцией ?:, используемой в си-подобных языках программирования. Безотносительно определённого языка программирования, тернарную операцию можно определить так: логическое выражение ? выражение 1 : выражение 2 Алгоритм работы операции следующий: Вычисляется логическое выражение. Если логическое выражение истинно, то вычисляется значение выражения выражение 1, в противном случае — значение выражения выражение 2. Вычисленное значение возвращается. Нужно обратить внимание, что вычисляется только одно из выражений: выражение 1 или выражение 2. Это сделано для оптимизации и, в некотором смысле, соответствует принципу ленивых вычислений. Некоторые примеры использования в PAWN:
Пример 1:
new— minimum = (a < b) ? a : b;
// Если 'a' будет меньше чем 'b' - то функция получит знач
Урок 3. Условные выражения в скриптинге ( что такое if, else,|| , & ,==,!=)
Урок 3. Условные выражения в скриптинге ( что такое if, else,|| , & ,==,!=)
Уроки по скриптингу для начинающих Условные выражения — это грубо говоря сравнение двух чисел и задача условий, для выбора какого из блоков кода следует выполнить далее.
Пример сравнения чисел:
x — = 5 x > 4 Для задачи условия существует выражение if(), которое от условий внутри круглых скобок, выберет какую часть кода следует выполнить.Пример:
if(x > 4){
//code Читается это выражение так: Если ( икс больше 4) { то выполняется этот код То есть если икс был бы меньше или равен четырем, то условие было бы не выполнено и код не выполнился. Так же есть выражение else ( используется только совместно с if())
if(x > 4){
//code1 }else{ //code2 Читается этот код так: Если ( икс больше 4) { то выполняется этот код №1 }Если не выполнено условие{ то выполняется этот код №2 Еще есть выражение else if:
if(x > 4){
//code1 }else if(x > 2){ //code2 }else{ //code3 Этот код будет чиаться так: Если ( икс больше 4) { то выполняется этот код №1 }если не выполнено условие и если( икс больше 2)Х то выполняется этот код №2 }Если не выполнено условие{ то выполняется этот код №3 Обратите внимание, что из всего блока if, будет работать только Один кусок кода, где условие было выполнено. А теперь вернемся к условным выражениям. Какие бывают условные выражения Для начала перечислю их всех (которые знаю сам): — Одно число меньше другого — Одно число больше другого == — Числа равны ( обратите внимания на то что ставится 2 знака ==, дальше думаю поймете почему) != — Не равно && —
Урок 2. Символы (текст) и работа с текстом (ответ на вопрос что такое %s)
Урок 2. Символы (текст) и работа с текстом (ответ на вопрос что такое %s)
Уроки по скриптингу для начинающих Наверное все знают что компьютеры работают только с цифрами 1 и 0, текст не исключение. Не буду вас грузить всеми нюансами, так как и сам если честно не до конца осведомлен что там и как работает, если вам все же очень интересно, то с легкостью сможете найти сами достаточное количество информации по этой теме. Исходя из выше сказанного можно сделать вывод что каждая строка, на самом деле набор цифр, символы представлены в ASCII кодировке, она представляет каждый символ своим числом, диапазон чисел от 0 до 255, сюда входят и прописные и заглавные буквы латинского алфавита, обратите внимание что большие и маленькие буквы — не одно и тоже. Видимо уже созрел вопрос, зачем 255 если в алфавите 26 букв плюс 26 заглавных, получается на много меньше чем 255, все правильно в эту кодировку входят еще и другие символы, но о них мы не будем сейчас говорить.
ASCII— кодировка и какое число за какую букву отвечает:test— — 4 символа, а массив под это слово должен иметь размер 5, 1 ячейку для последнего пустого символа.new— StringPlayerName[] = "Kotelov"
A-Z диапозон 65-90. 65 = 'A' и 90 = 'Z'. a-z диапозон 97-122. 97 = 'a' и 122 = 'z'. Заметили разницу между большими и маленькими буквами? Каждая строка обязана заканчиваться символом 0. То есть если в строке найдено пустое значение это конец строки. По этому все массивы должны иметь на не 1 размера больше чем текст.
Запись строк в массив Предположим мы хотим поместить имя игрока в массив, допустим имя будет Kotelov, в нем 7 символов, значит необходим массив с размерностью 8
При создании нового массива и записи в него слова, размер массива указывать не нужно, компилятор сделает это сам! Создание двумерных массивов Допустим нам необходимо запомнить все имена игроков на сервере. Для этого нам понадобится массив, который бы запомнил связку айди игрока с его именем. Выглядит это так: Представим что у нас 3 игрока на сервере с именами Nick1 Nick2 Nick3 и их айди 1 2 3
//Объявление двумерного массива
new PlayersName[32][] //32 максимальное количество игроков на сервере, второй массив оставляем без размера
//Заполнение двумерного массива
PlayersName[0][] = "Nick1" PlayersName[1][] = "Nick2" PlayersName[2][] = "Nick3"
get_user_name(PlayersName[1],name,32)
Объявление массива и его заполнение:
ne
- Войдите, чтобы ответить в этой теме.