Дата: 13.01.2011, Четверг, 12:52:02 | Сообщение # $NUMBER
Группа: Проверенные
Сообщений: 50
Хочу поделиться с вами одним из способов обработки команд, введенных игроком (OnPlayerCommandText). Так как в программировании важна декомпозиция, то логично было бы описывать обработку различных команд в разных файлах исходного кода (команды /buyhouse /setrent в файле описывающем систему домов, команды /ban /kick в отдельном файле с админскими командами и тд), и сейчас я покажу один из способов это реализовать. Для начала создаем файл command.inc, в нем у нас будет описан паблик OnPlayerCommandText. Идея заключается в том, чтобы для каждой команды создать свою функцию, а в OnPlayerCommandText определять какая функция соответствует введенной команде и вызывать ее, передав ей массив введенных параметров. С начала напишем саму функцию, которая будет превращать строку в двумерный массив параметров, первым из которых (под номером 0) будет название самой функции, зачем увидите дальше. Вот собственно ее код: Code cmdtext2params(const cmdtext[], params[][], size1 = sizeof params, size2 = sizeof params[]) { new currentparam; new n; new c = 1; // пропускаем слэш while(cmdtext[c]) { if(cmdtext[c] != ' ') { if(currentparam >= size1) break; if(n < size2-1) params[currentparam][n++] = cmdtext[c]; } else if(cmdtext[c+1] && cmdtext[c+1] != ' ') { currentparam++; n=0; } c++; } #if defined DEBUG for(n=0;n<min(currentparam+1,size1);n++) printf("cmd param %d: %s", n, params[n]); #endif } Теперь нам потребуется написать несколько макросов, облегчающих добавление новой команды. Code #define cmd(%1) if(strcmp(#%1,params[0],true)==0){cmd_%1(playerid);return(1);} #define cmdf(%1) if(strcmp(#%1,params[0],true)==0){cmdf_%1(playerid,params);return(1);}
#define altername(%1,%2) if(strcmp(#%2,params[0],true)==0){cmd_%1(playerid);return(1);} #define alternamef(%1,%2) if(strcmp(#%2,params[0],true)==0){cmdf_%1(playerid,params);return(1);} Первый макрос создан для команд без параметров, второй для команд с параметрами, третий и четвертый позволяют задавать альтернативные имена для команд. В конце файла на всякий случай убираем макросы. Code #undef cmd #undef cmdf
#undef altername #undef alternamef Теперь наконец опишем саму функцию OnPlayerCommandText Code public OnPlayerCommandText(playerid, cmdtext[]) { new params[7][20]; // массив параметров cmdtext2params(cmdtext, params); // выдираем параметры из строки if(!params[0][0]) return 0; // если нулевой параметр(имя команды) не заданно, то делать нам тут нечего - возвращаем ноль // теперь собственно список самих команд: cmd(kill) altername(kill,умри) // задаем альтернативное имя для команды kill cmdf(givemoney) alternamef(givemoney,gm) return 0; } В ней перечислены две команды - одна с параметрами, другая без. И альтернативные имена для каждой из них. Наш макрос преобразует каждую из этих строчек в сравнение значения в скобках с введенной командой из params[0] и в случае совпадения вызовет функцию с именем cmdf_имякоманды и параметрами playerid и params. Обратите внимание, что в местах использования макроса мы не ставим точку с запятой, а между параметрами altername не ставим лишних пробелов. Создать русскоязычную команду можно только через altername/alternamef. Теперь в отдельном файле опишем функции соответствующие нашим командам. Code cmd_kill(playerid) { SetPlayerHealth(playerid, 0); }
cmdf_givemoney(playerid, params[][]) { if(!IsPlayerAdmin(playerid)) { SendClientMessage(playerid, COLOR_RED, "У вас нет прав на использование этой команды."); return 1; } if(!params[1][0] || !params[2][0]) { // удобная проверка на все необходимые параметры в одном месте. new string[MAX_STRING]; /* за счет передачи имени введенной команды в params[0] - хелп будет универсален для различных имен команды */ format(string, sizeof string, "ИСПОЛЬЗОВАНИЕ: /%s [playerid] [money]", params[0]); SendClientMessage(playerid, COLOR_HELP, string); return 1; } new player = strval(params[1]); if(!IsPlayerConnected(player)) { SendClientMessage(playerid, COLOR_RED, "Нет такого игрока."); return 1; } new money = strval(params[2]); GivePlayerMoney(player, money); return 1; } Так как параметры уже разделены, мы можем легко проверить какой из них задан а какой нет (params[][0] не равен нулю). А так как у нас для одной функции существует несколько имен и чтобы для /gm не выдавался хелп с описанием /givemoney мы форматируем строчку используя введенную игроком команду (передается в params[0]). В функцию cmd_kill никаких параметров не передается, так как они там не нужны. command.inc - http://pastebin.com/7c8Y9FJY new.pwn - http://pastebin.com/STsZMusG // Автор урока: Maccer (Как я понял) // Источник: sa-mp.com
|