DeimoS
30.01.2014, 15:56
Я вас категорически приветствую, друзья!
Сегодня я постараюсь объяснить вам, что же за зверь такой, этот stock, и с чем его едят. И сделать это я постараюсь на человеческом языке, дабы всем было понятно. Начнём.
Определение Stock:
Stock - Маркер компилятора, указывающий компилятору на исключение кода функции из конечного amx файла, если функция не используется в коде скрипта © DeimoS
Иными словами код функции или переменные, созданные с использованием маркера "stock", не будут включены в скомпилированную версию мода, если они не будут использованы в моде.
Если же создать функцию/переменную с использованием других маркеров, компилятор включит их в финальную версию, сигнализирует о их бесполезности и AMX машина (сервер) выделит для них память
Способы применения Stock:
Переменные:
Выглядит это так
Целочисленный тип
Вещественный тип
Строка
Одномерный массив
Двумерный массив
new
new variable;
new Float:variable;
new variable[10];
new variable[2] =
{1, 7};
new variable[2][1] =
{ {8}, {15} };
stock
stock variable;
stock Float:variable;
stock variable[10];
stock variable[2] =
{1, 7};
stock variable[2][1] =
{ {8}, {15} };
Использование переменных в stock точно такое же, как и использование переменных в new. В чём же различие, спросите Вы?
А различие именно в том, что stock не регистрируется в памяти сервера. То есть, если переменная объявлена через stock, но в коде она нигде не используется, компилятор автоматически удалит её при компиляции (имеется ввиду то, что в .amx варианте вашего кода этой переменной не будет). Следовательно лишней памяти сервер не будет выделять для этой переменной. Данное правило распространяется и на функции, так что запоминаем сразу (ниже упоминаний об этом не будет).
Но стоит помнить, что Вы никак не узнаете, используется переменная или нет, без ручного поиска кода, в котором используется эта переменная. Ибо, в случае с stock, при компилировании данная ошибка отображаться не будет:
warning 204: symbol is assigned a value that is never used: "%s"
Функции:
С помощью stock Вы можете единственный раз написать определённый код и после вызывать его всего лишь написав код вызова stock. Но и не только. С помощью stock Вы можете сильно облегчить свою жизнь при написании различных сложных функций :) И ниже я попробую привести несколько примеров кода для того, чтобы Вы поняли о чём я говорю :)
Создание stock:
Новый stock создаётся вне других функций (public/stock). То есть, точно так же, как и public, но без forward.
Пример создания stock:
stock StockName(arguments)
{
return 1;
}
Где:
StockName - название нашего stock
arguments - название аргументов, в которые будет помещена информация для обработки. Названия могут быть любыми, как и в случае с переменными. Про ограничение на количество этих аргументов в одном stock мне не известно. Если Вы об это что-то знаете, просьба отписаться с предоставлением каких-либо доказательств =) Но уж точно не менее 8 аргументов использовать можно (личный опыт :) )
Пример использования stock:
Допустим, у нас есть диалог, который мы используем в нескольких участках кода (одинаковый). Чтобы каждый раз не писать его, мы можем создать stock с ним
stock ShowDialog(id)
{
new string[1001];//Да, текст занимает 1001 ячейку. Точнее 1000 ячеек, но нужно же ещё выделить одну для нулевого символа =) И теперь представьте, что если такой диалог нужно вызывать в нескольких местах, каждый раз придется выделять 1001 ячейку. То есть, при создании двух таких переменных, Вы уже выделите 2002 ячейки, при создании трёх - 3003 и т.д. Согласитесь, нерационально это =) (Для самых внимательных: Да, можно создать глобальную переменную. Но зачем забивать мод кучей одинаковых строк, когда можно написать их 1 раз?)
format(string, sizeof(string), "Тут длинный текст, который будет занимать много места в коде. Да и для его хранения придется создавать каждый раз переменную, а это трата памяти. Зачем нам это? Лучше раз создать stock, в котором 1 раз объявить переменную, и уже работать с этим stock");
format(string, sizeof(string), "%sТут длинный текст, который будет занимать много места в коде. Да и для его хранения придется создавать каждый раз переменную, а это трата памяти. Зачем нам это? Лучше раз создать stock, в котором 1 раз объявить переменную, и уже работать с этим stock",string);
format(string, sizeof(string), "%sТут длинный текст, который будет занимать много места в коде. Да и для его хранения придется создавать каждый раз переменную, а это трата памяти. Зачем нам это? Лучше раз создать stock, в котором 1 раз объявить переменную, и уже работать с этим stock",string);
format(string, sizeof(string), "%sТут длинный текст, который будет занимать много места в коде. Да и для его хранения придется создавать каждый раз переменную, а это трата памяти. Зачем нам это? Лучше раз создать stock, в котором 1 раз объявить переменную, и уже работать с этим stock",string);
ShowPlayerDialog(id, 0, DIALOG_STYLE_MSGBOX, "Названия диалога", string, "Кнопа 1", "Кнопа 2");
return 1;
}
Примечание: Хоть для отображения диалога требуется аргумент "playerid", в stock мы указали имя аргумента "id". Поэтому в ShowPlayerDialog мы должны указать именно "id", а уже при вызове stock мы присвоим значение аргументу "id" значение аргумента "playerid".
Обратите внимание, что "id", при создании stock, я написал лишь для того, чтобы Вы поняли, что имя аргумента может быть любое. Вы можете сразу написать "playerid" и в ShowPlayerDialog использовать "playerid". А можете написать "Deimos_noob" и так же использовать в диалоге уже "Deimos_noob". Главное не забывайте менять название аргумента в нативных функциях (кликабельно) (http://wiki.sa-mp.com/wiki/Category:Scripting_Functions) внутри stock на такое, какое Вы указали при создании stock (примером является "id" в создании stock и "playerid" в ShowPlayerDialog). Но менять название нужно именно в тех аргументах, значение которых Вы будете "доставлять" в код, находящийся в stock, при вызове этого stock. В этом примере это был "palyerid" и ниже Вы это увидите
Ну и создадим команду для отображения этого диалога
if (strcmp("/showmydialogue", cmdtext, true, 10) == 0)
{
SendClientMessage(playerid,0xFF0000FF,"А вот и диалог");
ShowDialog(playerid);//Вот тут мы указали откуда именно брать значение для "id". В данном случае в "id" поместится значение ID игрока. Но это может быть и не ID, а та информация, которая вам нужна. Ниже я приведу примеры
return 1;
}
Ну и при коннекте игрока вызовем диалог
public OnPlayerConnect(playerid)
{
ShowDialog(playerid);
return 1;
}
А теперь попробуем создать команду для передачи денег от одного игрока к другому с помощью stock. Сначала создадим stock с тремя аргументами, в которые запишем ID обоих игроков и сумму передачи денег
stock PlayerMoneyToPlayer(player1, player2, money)//Опять же, имена аргументов выбираете только Вы. Я создаю такие только для того, чтобы Вы чётко видели что и где менять
{
new string[71];//57 символов занимает весь текст. Максимальная сумма денег на руках игрока не может превышать 11 символов, поэтому к 57 прибавляем 11 и выделяем 3 ячейки для хранения трёхзначного ID игрока (не видел онлайн в 1000 человек ещё, так что 3 символа хватит). 57 + 11 + 3 = 71
GivePlayerMoney(player1,-=money);//Отнимем сумму у игрока, который решил передать деньги
GivePlayerMoney(player2,+=money);//Выдадим деньги игроку, которому первый игрок решил передать деньги
format(string,sizeof(string),"Вы передали %d$ игроку с ID %d", money, player2);
SendClientMessage(player1,0xFFFFFFFF,string);//Оповестим первого игрока о успешной передаче денег
format(string,sizeof(string),"Вам передали %d$. ID игрока, передавшего вам деньги - %d", money, player2);
SendClientMessage(player2,0xFFFFFFFF,string);//Оповестим второго игрока о успешном получении денег
return 1;//Отсылаем серверу сигнал о том, что всё прошло успешно и можно продолжать выполнять код после stock.
}
И теперь создадим команду, в которой и присвоим нужные значения для аргументов stock
Этот код нужно вставлять в самое начало паблика OnPlayerCommandText, если его нет. Без него функция srtok работать не будет
new cmd[128], idx[128], tmp[128];//Создадим переменные, которые нам понадобятся для дальнейшей работы с функцией strtok
cmd = strtok(cmdtext, idx);//Приравняем нашу переменную к значению strtok и теперь, при создании команду, будем использовать не cmdtext, а cmd (иначе strtok работать не будет).
if (strcmp("/pay", cmd, true, 10) == 0)
{
tmp = strtok(cmdtext, idx);//strtok начнёт искать символы после пробела, которые игрок введёт при использовании команды
if(!strlen(tmp)) return SendClientMessage(playerid,0xFF0000AA,"Вы не ввели ID игрока");//Если игрок не написал ничего после первого пробела - оповестим его об этом и оборвём выполнение команды
new giveplayerid = strval(tmp);//strval преобразует введённые игроком данные в число. Если игрок введёт текст, strval выдаст значение 0. Запишем в giveplayerid ID игрока, которому надо передать деньги
if(playerid == giveplayerid) return SendClientMessage(playerid,0xFF0000AA,"Вы ввели свой ID. Себе деньги передать нельзя");//Если игрок ввёл свой ID, оповестим его об этом и не дадим перевести деньги (это делает return)
if(!IsPlayerConnected(giveplayerid)) return SendClientMessage(playerid,0xFF0000AA,"Данного игрока нет в сети");//Если игрок ввёл ID игрока, которого нет на сервере, оповестим его об этом и не дадим перевести деньги
tmp = strtok(cmdtext, idx);//Дадим сигнал моду для поиска ещё одного пробела
if(!strlen(tmp)) return SendClientMessage(playerid,0xFF0000AA,"Вы не ввели сумму для передачи");//Если игрок не написал ничего после второго пробела - оповестим его об этом и оборвём выполнение команды
new pmoney = strval(tmp);//Запишем сумму, которую игрок введёт после ввода IP
if(pmoney < GetPlayerMoney(playerid)) return SendClientMessage(playerid,0xFF0000AA,"У вас недостаточно денег на руках для передачи");//Если денег у игрока меньше чем он ввёл в команду, оповестим его об этом и прервём выполнение кода
//Теперь пора вызывать наш stock. После команды будет объяснение именно этого кода
PlayerMoneyToPlayer(playerid, giveplayerid, pmoney);//Передаём деньги с помощью stock
return 1;
}
"playerid" хранит значение ID игрока, который ввёл команду и передаст это значение аргументу "player1" из нашего stock
"giveplayerid" имеет значение ID игрока, которому надо передать деньги и передаст это значение аргументу "player2" из нашего stock
"pmoney" имеет значение суммы денег для передачи и передаст это значение аргументу "money" из нашего stock
Если кто-то не понял то, как я определил это всё, объясню по другому. Ниже будет предоставлен сам stock (таким, каким мы его создали) и способ вызова этого stock. Одинаковым цветом я выделю те аргументы, значения которых передаются от вызова stock к самому stock
stock PlayerMoneyToPlayer(player1, player2, money)
PlayerMoneyToPlayer(playerid, giveplayerid, pmoney);
То есть, аргументы отделяют друг от друга запятыми. Следовательно, при вызове stock, нам нужно расположить аргументы с данными в таком порядке, чтобы нужные данные присвоились нужному аргументу в stock
В данном примере я покажу вам как передать определённый текст с помощью stock на примере команды личных сообщений. Данный stock будет содержать уже аж 5 аргументов, два из которых будут содержать ники игроков, два будут содержать ID и один будет содержать текст. Да, с помощью strok можно и такое :)
stock PrivateMessage(name1[], name2[], playerid, giveplayerid, text[])//name1[] и name2[] будут хранить ники, playerid и giveplayerid будут хранить ID игроков, а text[] - текст. Эти скобки - "[]" - означают, что в аргументе будет хранится текст. Все типы аргументов будут описаны ниже
{
new Message[169];//Создадим массив, в котором будет хранится текст
format(Message,sizeof(Message),">> %s[%d]: %s",name2,giveplayerid,text);//Оповестим первого игрока таким сообщением о том, что сообщение доставлено второму игроку.
//Заметьте, что тут мы уже используем name2 и text без скобок. Так же и с остальными типами аргументов (о которых расскажу ниже)
SendClientMessage(playerid,0xFF0000FF,Message);
format(Message,sizeof(Message),"<< %s[%d]: %s",name1,playerid,text);//Оповестим второго игрока таким сообщением о том, что первый игрок прислал ему сообщение
SendClientMessage(giveplayerid,0xFF0000FF,Message);
return 1;
}
Ну и теперь сама команда
Этот код нужно вставлять в самое начало паблика OnPlayerCommandText, если его нет. Без него функция srtok работать не будет
new cmd[128], idx[128], tmp[128];//Создадим переменные, которые нам понадобятся для дальнейшей работы с функцией strtok
cmd = strtok(cmdtext, idx);//Приравняем нашу переменную к значению strtok и теперь, при создании команду, будем использовать не cmdtext, а cmd (иначе strtok работать не будет).
if(strcmp(cmd, "/pm", true) == 0)
{
new PlayerName[1][MAX_PLAYER_NAME]);//Создадим двумерный массив для записи ников обоих игроков
tmp = strtok(cmdtext, idx);//strtok начнёт искать символы после пробела, которые игрок введёт при использовании команды
if(!strlen(tmp)) return SendClientMessage(playerid,0xFF0000AA,"Вы не ввели ID игрока");//Если игрок не написал ничего после первого пробела - оповестим его об этом и оборвём выполнение команды
new giveplayerid = strval(tmp);//strval преобразует введённые игроком данные в число. Если игрок введёт текст, strval выдаст значение 0. Запишем в giveplayerid ID игрока, которому надо передать деньги
GetPlayerName(playerid, PlayerName[0], MAX_PLAYER_NAME);//Запишем ник первого игрока
GetPlayerName(giveplayerid, PlayerName[1], MAX_PLAYER_NAME);//Запишем ник второго игрока
if(playerid == giveplayerid) return SendClientMessage(playerid,0xFF0000AA,"Вы ввели свой ID. Себе писать в личку нельзя");//Если игрок ввёл свой ID, оповестим его об этом и не дадим написать личное сообщение (это делает return)
if(!IsPlayerConnected(giveplayerid)) return SendClientMessage(playerid,0xFF0000AA,"Данного игрока нет в сети");//Если игрок ввёл ID игрока, которого нет на сервере, оповестим его об этом и не дадим перевести деньги
//Далее идёт код, который "ищет" введённый игроком текст
new length = strlen(cmdtext);
while ((idx < length) && (cmdtext[idx] <= ' '))
{
idx++;
}
new offset = idx;
new result[64];
while ((idx < length) && ((idx - offset) < (sizeof(result) - 1)))
{
result[idx - offset] = cmdtext[idx];
idx++;
}
result[idx - offset] = EOS;
//Поиск текста окончен
if(!strlen(result)) return SendClientMessage(playerid,0xFF0000AA,"Вы не ввели текст сообщения");//Если игрок не написал ничего - оповестим его об этом и оборвём выполнение команды
if(strlen(result)>128) return SendClientMessage(playerid,0xFF0000AA,"Максимальная длинна сообщения - 128 символов");//При написании stock, мы создали массив Message. Когда я рассчитывал число ячеек, которые мы выделим для записи текста, я предоставил для текста 128 ячеек. Поэтому сделаем ограничение, дабы текст отобразился корректно
//Всё, что нужно для формирования "вызова" stock, у нас уже имеется. Теперь делаем сам "вызов"
PrivateMessage(PlayerName[0], PlayerName[1], playerid, giveplayerid, (result));//Формируем и отправляем запрос
return 1;
}
Типы данных для аргументов:
У аргументов stock, как и аргументов public, есть типы данных. Эти типы точно такие же, как и у переменных. Всего 4 типа:
Вещественный (дробное число)
stock StockName(Float:arguments)
"Float:arguments"
Логический (bool. То есть true/false)
stock StockName(bool:arguments)
"bool:arguments"
Целочисленный (целые числа)
stock StockName(arguments)
"arguments"
Строковый (символы, то бишь текст)
stock StockName(arguments[])
"arguments[]"
Примечание: Повторюсь, все типы данных работают так же, как и у переменных. Следовательно, использовать их нужно без аргументов ("Float","[]"."bool:"). Пример имеется в примере 3 (извиняюсь за тавтологию).
Прочие виды аргументов:
Ссылка (&):
Данный вид возвращает значения аргумента, получившиеся после выполнения кода функции. (аналогично "return")
stock StockName(&arguments)
"&arguments"
stock Calculator(&n_1, &n_2)//Создадим новый stock, в котором оба аргумента будут являться ссылками
{
n_1 += 3;//К значению первого аргумента прибавим тройку
n_2 -= 17;//От значения второго аргумента отнимем семнадцать
return 1;
}//Выполнение кода окончено и все аргументы, созданные как ссылки, вернут свои значения в место вызова функции
main()
{
new num[2];
num[0] = 10;
num[1] = 20;
printf("\nДо вызова\nЗначение[0] = %d\nЗначение[1] = %d\n",num[0],num[1]);//До вызова стока значения переменных будут равны заданным ранее значениям
Calculator(num[0], num[1]);//До вызова переменные будут равны 10 и 20, а после выполнения их значения станут равны 13 и 3
printf("\nПосле вызова\nЗначение[0] = %d\nЗначение[1] = %d\n",num[0],num[1]);//После вызова значения будут уже другими
}
На этом всё =)
Если есть какие-либо вопросы, если что-то непонятно объяснено или есть какие-либо дополнения/исправления для данного урока, прошу написать об этом ниже. Всем постараюсь помочь, все мнения приму к сведению.
С вами был DeimoS. Спасибо за внимание
Автор урока - DeimoS
При копировании данного материала, обязательно указывайте автора и ссылку на данный урок
Сегодня я постараюсь объяснить вам, что же за зверь такой, этот stock, и с чем его едят. И сделать это я постараюсь на человеческом языке, дабы всем было понятно. Начнём.
Определение Stock:
Stock - Маркер компилятора, указывающий компилятору на исключение кода функции из конечного amx файла, если функция не используется в коде скрипта © DeimoS
Иными словами код функции или переменные, созданные с использованием маркера "stock", не будут включены в скомпилированную версию мода, если они не будут использованы в моде.
Если же создать функцию/переменную с использованием других маркеров, компилятор включит их в финальную версию, сигнализирует о их бесполезности и AMX машина (сервер) выделит для них память
Способы применения Stock:
Переменные:
Выглядит это так
Целочисленный тип
Вещественный тип
Строка
Одномерный массив
Двумерный массив
new
new variable;
new Float:variable;
new variable[10];
new variable[2] =
{1, 7};
new variable[2][1] =
{ {8}, {15} };
stock
stock variable;
stock Float:variable;
stock variable[10];
stock variable[2] =
{1, 7};
stock variable[2][1] =
{ {8}, {15} };
Использование переменных в stock точно такое же, как и использование переменных в new. В чём же различие, спросите Вы?
А различие именно в том, что stock не регистрируется в памяти сервера. То есть, если переменная объявлена через stock, но в коде она нигде не используется, компилятор автоматически удалит её при компиляции (имеется ввиду то, что в .amx варианте вашего кода этой переменной не будет). Следовательно лишней памяти сервер не будет выделять для этой переменной. Данное правило распространяется и на функции, так что запоминаем сразу (ниже упоминаний об этом не будет).
Но стоит помнить, что Вы никак не узнаете, используется переменная или нет, без ручного поиска кода, в котором используется эта переменная. Ибо, в случае с stock, при компилировании данная ошибка отображаться не будет:
warning 204: symbol is assigned a value that is never used: "%s"
Функции:
С помощью stock Вы можете единственный раз написать определённый код и после вызывать его всего лишь написав код вызова stock. Но и не только. С помощью stock Вы можете сильно облегчить свою жизнь при написании различных сложных функций :) И ниже я попробую привести несколько примеров кода для того, чтобы Вы поняли о чём я говорю :)
Создание stock:
Новый stock создаётся вне других функций (public/stock). То есть, точно так же, как и public, но без forward.
Пример создания stock:
stock StockName(arguments)
{
return 1;
}
Где:
StockName - название нашего stock
arguments - название аргументов, в которые будет помещена информация для обработки. Названия могут быть любыми, как и в случае с переменными. Про ограничение на количество этих аргументов в одном stock мне не известно. Если Вы об это что-то знаете, просьба отписаться с предоставлением каких-либо доказательств =) Но уж точно не менее 8 аргументов использовать можно (личный опыт :) )
Пример использования stock:
Допустим, у нас есть диалог, который мы используем в нескольких участках кода (одинаковый). Чтобы каждый раз не писать его, мы можем создать stock с ним
stock ShowDialog(id)
{
new string[1001];//Да, текст занимает 1001 ячейку. Точнее 1000 ячеек, но нужно же ещё выделить одну для нулевого символа =) И теперь представьте, что если такой диалог нужно вызывать в нескольких местах, каждый раз придется выделять 1001 ячейку. То есть, при создании двух таких переменных, Вы уже выделите 2002 ячейки, при создании трёх - 3003 и т.д. Согласитесь, нерационально это =) (Для самых внимательных: Да, можно создать глобальную переменную. Но зачем забивать мод кучей одинаковых строк, когда можно написать их 1 раз?)
format(string, sizeof(string), "Тут длинный текст, который будет занимать много места в коде. Да и для его хранения придется создавать каждый раз переменную, а это трата памяти. Зачем нам это? Лучше раз создать stock, в котором 1 раз объявить переменную, и уже работать с этим stock");
format(string, sizeof(string), "%sТут длинный текст, который будет занимать много места в коде. Да и для его хранения придется создавать каждый раз переменную, а это трата памяти. Зачем нам это? Лучше раз создать stock, в котором 1 раз объявить переменную, и уже работать с этим stock",string);
format(string, sizeof(string), "%sТут длинный текст, который будет занимать много места в коде. Да и для его хранения придется создавать каждый раз переменную, а это трата памяти. Зачем нам это? Лучше раз создать stock, в котором 1 раз объявить переменную, и уже работать с этим stock",string);
format(string, sizeof(string), "%sТут длинный текст, который будет занимать много места в коде. Да и для его хранения придется создавать каждый раз переменную, а это трата памяти. Зачем нам это? Лучше раз создать stock, в котором 1 раз объявить переменную, и уже работать с этим stock",string);
ShowPlayerDialog(id, 0, DIALOG_STYLE_MSGBOX, "Названия диалога", string, "Кнопа 1", "Кнопа 2");
return 1;
}
Примечание: Хоть для отображения диалога требуется аргумент "playerid", в stock мы указали имя аргумента "id". Поэтому в ShowPlayerDialog мы должны указать именно "id", а уже при вызове stock мы присвоим значение аргументу "id" значение аргумента "playerid".
Обратите внимание, что "id", при создании stock, я написал лишь для того, чтобы Вы поняли, что имя аргумента может быть любое. Вы можете сразу написать "playerid" и в ShowPlayerDialog использовать "playerid". А можете написать "Deimos_noob" и так же использовать в диалоге уже "Deimos_noob". Главное не забывайте менять название аргумента в нативных функциях (кликабельно) (http://wiki.sa-mp.com/wiki/Category:Scripting_Functions) внутри stock на такое, какое Вы указали при создании stock (примером является "id" в создании stock и "playerid" в ShowPlayerDialog). Но менять название нужно именно в тех аргументах, значение которых Вы будете "доставлять" в код, находящийся в stock, при вызове этого stock. В этом примере это был "palyerid" и ниже Вы это увидите
Ну и создадим команду для отображения этого диалога
if (strcmp("/showmydialogue", cmdtext, true, 10) == 0)
{
SendClientMessage(playerid,0xFF0000FF,"А вот и диалог");
ShowDialog(playerid);//Вот тут мы указали откуда именно брать значение для "id". В данном случае в "id" поместится значение ID игрока. Но это может быть и не ID, а та информация, которая вам нужна. Ниже я приведу примеры
return 1;
}
Ну и при коннекте игрока вызовем диалог
public OnPlayerConnect(playerid)
{
ShowDialog(playerid);
return 1;
}
А теперь попробуем создать команду для передачи денег от одного игрока к другому с помощью stock. Сначала создадим stock с тремя аргументами, в которые запишем ID обоих игроков и сумму передачи денег
stock PlayerMoneyToPlayer(player1, player2, money)//Опять же, имена аргументов выбираете только Вы. Я создаю такие только для того, чтобы Вы чётко видели что и где менять
{
new string[71];//57 символов занимает весь текст. Максимальная сумма денег на руках игрока не может превышать 11 символов, поэтому к 57 прибавляем 11 и выделяем 3 ячейки для хранения трёхзначного ID игрока (не видел онлайн в 1000 человек ещё, так что 3 символа хватит). 57 + 11 + 3 = 71
GivePlayerMoney(player1,-=money);//Отнимем сумму у игрока, который решил передать деньги
GivePlayerMoney(player2,+=money);//Выдадим деньги игроку, которому первый игрок решил передать деньги
format(string,sizeof(string),"Вы передали %d$ игроку с ID %d", money, player2);
SendClientMessage(player1,0xFFFFFFFF,string);//Оповестим первого игрока о успешной передаче денег
format(string,sizeof(string),"Вам передали %d$. ID игрока, передавшего вам деньги - %d", money, player2);
SendClientMessage(player2,0xFFFFFFFF,string);//Оповестим второго игрока о успешном получении денег
return 1;//Отсылаем серверу сигнал о том, что всё прошло успешно и можно продолжать выполнять код после stock.
}
И теперь создадим команду, в которой и присвоим нужные значения для аргументов stock
Этот код нужно вставлять в самое начало паблика OnPlayerCommandText, если его нет. Без него функция srtok работать не будет
new cmd[128], idx[128], tmp[128];//Создадим переменные, которые нам понадобятся для дальнейшей работы с функцией strtok
cmd = strtok(cmdtext, idx);//Приравняем нашу переменную к значению strtok и теперь, при создании команду, будем использовать не cmdtext, а cmd (иначе strtok работать не будет).
if (strcmp("/pay", cmd, true, 10) == 0)
{
tmp = strtok(cmdtext, idx);//strtok начнёт искать символы после пробела, которые игрок введёт при использовании команды
if(!strlen(tmp)) return SendClientMessage(playerid,0xFF0000AA,"Вы не ввели ID игрока");//Если игрок не написал ничего после первого пробела - оповестим его об этом и оборвём выполнение команды
new giveplayerid = strval(tmp);//strval преобразует введённые игроком данные в число. Если игрок введёт текст, strval выдаст значение 0. Запишем в giveplayerid ID игрока, которому надо передать деньги
if(playerid == giveplayerid) return SendClientMessage(playerid,0xFF0000AA,"Вы ввели свой ID. Себе деньги передать нельзя");//Если игрок ввёл свой ID, оповестим его об этом и не дадим перевести деньги (это делает return)
if(!IsPlayerConnected(giveplayerid)) return SendClientMessage(playerid,0xFF0000AA,"Данного игрока нет в сети");//Если игрок ввёл ID игрока, которого нет на сервере, оповестим его об этом и не дадим перевести деньги
tmp = strtok(cmdtext, idx);//Дадим сигнал моду для поиска ещё одного пробела
if(!strlen(tmp)) return SendClientMessage(playerid,0xFF0000AA,"Вы не ввели сумму для передачи");//Если игрок не написал ничего после второго пробела - оповестим его об этом и оборвём выполнение команды
new pmoney = strval(tmp);//Запишем сумму, которую игрок введёт после ввода IP
if(pmoney < GetPlayerMoney(playerid)) return SendClientMessage(playerid,0xFF0000AA,"У вас недостаточно денег на руках для передачи");//Если денег у игрока меньше чем он ввёл в команду, оповестим его об этом и прервём выполнение кода
//Теперь пора вызывать наш stock. После команды будет объяснение именно этого кода
PlayerMoneyToPlayer(playerid, giveplayerid, pmoney);//Передаём деньги с помощью stock
return 1;
}
"playerid" хранит значение ID игрока, который ввёл команду и передаст это значение аргументу "player1" из нашего stock
"giveplayerid" имеет значение ID игрока, которому надо передать деньги и передаст это значение аргументу "player2" из нашего stock
"pmoney" имеет значение суммы денег для передачи и передаст это значение аргументу "money" из нашего stock
Если кто-то не понял то, как я определил это всё, объясню по другому. Ниже будет предоставлен сам stock (таким, каким мы его создали) и способ вызова этого stock. Одинаковым цветом я выделю те аргументы, значения которых передаются от вызова stock к самому stock
stock PlayerMoneyToPlayer(player1, player2, money)
PlayerMoneyToPlayer(playerid, giveplayerid, pmoney);
То есть, аргументы отделяют друг от друга запятыми. Следовательно, при вызове stock, нам нужно расположить аргументы с данными в таком порядке, чтобы нужные данные присвоились нужному аргументу в stock
В данном примере я покажу вам как передать определённый текст с помощью stock на примере команды личных сообщений. Данный stock будет содержать уже аж 5 аргументов, два из которых будут содержать ники игроков, два будут содержать ID и один будет содержать текст. Да, с помощью strok можно и такое :)
stock PrivateMessage(name1[], name2[], playerid, giveplayerid, text[])//name1[] и name2[] будут хранить ники, playerid и giveplayerid будут хранить ID игроков, а text[] - текст. Эти скобки - "[]" - означают, что в аргументе будет хранится текст. Все типы аргументов будут описаны ниже
{
new Message[169];//Создадим массив, в котором будет хранится текст
format(Message,sizeof(Message),">> %s[%d]: %s",name2,giveplayerid,text);//Оповестим первого игрока таким сообщением о том, что сообщение доставлено второму игроку.
//Заметьте, что тут мы уже используем name2 и text без скобок. Так же и с остальными типами аргументов (о которых расскажу ниже)
SendClientMessage(playerid,0xFF0000FF,Message);
format(Message,sizeof(Message),"<< %s[%d]: %s",name1,playerid,text);//Оповестим второго игрока таким сообщением о том, что первый игрок прислал ему сообщение
SendClientMessage(giveplayerid,0xFF0000FF,Message);
return 1;
}
Ну и теперь сама команда
Этот код нужно вставлять в самое начало паблика OnPlayerCommandText, если его нет. Без него функция srtok работать не будет
new cmd[128], idx[128], tmp[128];//Создадим переменные, которые нам понадобятся для дальнейшей работы с функцией strtok
cmd = strtok(cmdtext, idx);//Приравняем нашу переменную к значению strtok и теперь, при создании команду, будем использовать не cmdtext, а cmd (иначе strtok работать не будет).
if(strcmp(cmd, "/pm", true) == 0)
{
new PlayerName[1][MAX_PLAYER_NAME]);//Создадим двумерный массив для записи ников обоих игроков
tmp = strtok(cmdtext, idx);//strtok начнёт искать символы после пробела, которые игрок введёт при использовании команды
if(!strlen(tmp)) return SendClientMessage(playerid,0xFF0000AA,"Вы не ввели ID игрока");//Если игрок не написал ничего после первого пробела - оповестим его об этом и оборвём выполнение команды
new giveplayerid = strval(tmp);//strval преобразует введённые игроком данные в число. Если игрок введёт текст, strval выдаст значение 0. Запишем в giveplayerid ID игрока, которому надо передать деньги
GetPlayerName(playerid, PlayerName[0], MAX_PLAYER_NAME);//Запишем ник первого игрока
GetPlayerName(giveplayerid, PlayerName[1], MAX_PLAYER_NAME);//Запишем ник второго игрока
if(playerid == giveplayerid) return SendClientMessage(playerid,0xFF0000AA,"Вы ввели свой ID. Себе писать в личку нельзя");//Если игрок ввёл свой ID, оповестим его об этом и не дадим написать личное сообщение (это делает return)
if(!IsPlayerConnected(giveplayerid)) return SendClientMessage(playerid,0xFF0000AA,"Данного игрока нет в сети");//Если игрок ввёл ID игрока, которого нет на сервере, оповестим его об этом и не дадим перевести деньги
//Далее идёт код, который "ищет" введённый игроком текст
new length = strlen(cmdtext);
while ((idx < length) && (cmdtext[idx] <= ' '))
{
idx++;
}
new offset = idx;
new result[64];
while ((idx < length) && ((idx - offset) < (sizeof(result) - 1)))
{
result[idx - offset] = cmdtext[idx];
idx++;
}
result[idx - offset] = EOS;
//Поиск текста окончен
if(!strlen(result)) return SendClientMessage(playerid,0xFF0000AA,"Вы не ввели текст сообщения");//Если игрок не написал ничего - оповестим его об этом и оборвём выполнение команды
if(strlen(result)>128) return SendClientMessage(playerid,0xFF0000AA,"Максимальная длинна сообщения - 128 символов");//При написании stock, мы создали массив Message. Когда я рассчитывал число ячеек, которые мы выделим для записи текста, я предоставил для текста 128 ячеек. Поэтому сделаем ограничение, дабы текст отобразился корректно
//Всё, что нужно для формирования "вызова" stock, у нас уже имеется. Теперь делаем сам "вызов"
PrivateMessage(PlayerName[0], PlayerName[1], playerid, giveplayerid, (result));//Формируем и отправляем запрос
return 1;
}
Типы данных для аргументов:
У аргументов stock, как и аргументов public, есть типы данных. Эти типы точно такие же, как и у переменных. Всего 4 типа:
Вещественный (дробное число)
stock StockName(Float:arguments)
"Float:arguments"
Логический (bool. То есть true/false)
stock StockName(bool:arguments)
"bool:arguments"
Целочисленный (целые числа)
stock StockName(arguments)
"arguments"
Строковый (символы, то бишь текст)
stock StockName(arguments[])
"arguments[]"
Примечание: Повторюсь, все типы данных работают так же, как и у переменных. Следовательно, использовать их нужно без аргументов ("Float","[]"."bool:"). Пример имеется в примере 3 (извиняюсь за тавтологию).
Прочие виды аргументов:
Ссылка (&):
Данный вид возвращает значения аргумента, получившиеся после выполнения кода функции. (аналогично "return")
stock StockName(&arguments)
"&arguments"
stock Calculator(&n_1, &n_2)//Создадим новый stock, в котором оба аргумента будут являться ссылками
{
n_1 += 3;//К значению первого аргумента прибавим тройку
n_2 -= 17;//От значения второго аргумента отнимем семнадцать
return 1;
}//Выполнение кода окончено и все аргументы, созданные как ссылки, вернут свои значения в место вызова функции
main()
{
new num[2];
num[0] = 10;
num[1] = 20;
printf("\nДо вызова\nЗначение[0] = %d\nЗначение[1] = %d\n",num[0],num[1]);//До вызова стока значения переменных будут равны заданным ранее значениям
Calculator(num[0], num[1]);//До вызова переменные будут равны 10 и 20, а после выполнения их значения станут равны 13 и 3
printf("\nПосле вызова\nЗначение[0] = %d\nЗначение[1] = %d\n",num[0],num[1]);//После вызова значения будут уже другими
}
На этом всё =)
Если есть какие-либо вопросы, если что-то непонятно объяснено или есть какие-либо дополнения/исправления для данного урока, прошу написать об этом ниже. Всем постараюсь помочь, все мнения приму к сведению.
С вами был DeimoS. Спасибо за внимание
Автор урока - DeimoS
При копировании данного материала, обязательно указывайте автора и ссылку на данный урок