Как написать свой мод для сервера самп

Кратко о том что мы будем делать.
Данные уроки будут посвящены написанию игрового мода sa-mp с new.pwn. Мод будет жанра RPG, написан на файловой системе с использованием инклуда mxINI.

Краткий план разработки на ближайшее время:

Основа Мода.
— Система Регистрации
— Загрузка сохранения аккаунта.
— Система Домов
— Система Бизнесов
— Система Транспорта
— Система Банка.

Это план на написание основы. После этого мод начнет заполнятся фракциями, работами и т.п.

Данный урок, будет посвящен началу разработки, и написанию системы регистрации, и загрузки сохранения аккаунта.
Пожалуй начнём.

Действие Первое. Нужные файлы, и настройка сервера:

Качаем последнюю версию сервера sa-mp с офф. сайта. ссылка
Распаковываем сервер в любую удобную для вас папку.
Открываем server.cfg, и меняем rcon_password changename, на свой пароль, из строки filterscripts, убираем все FS которые включены. Меняем gamemode, на new.
Качаем последнюю версию инклуда mxINI. ссылка
Открываем папку pawno, в папке с вашим сервером, папку include, и ложем инклуд mxINI, в эту папку.
Заходи в папку gamemodes, и удаляем все моды которые там есть ( для удобства ).
Заходим в папку pawno, и открываем программу pawno.exe.
Слева, в углу, нажимаем на кнопку new.
Пред вами то, что в ближайшее время, будет нашим модом.
Нажимаем F5, и нам предлагают выбрать папку, и имя будущего мода. Выбираем папку gamemodes, в папке с вашим сервером, и имя файла задаём new .
Пробуем запустить мод, зайдя в папку с сервером, и запустим файл samp-server.exe .
Если сервер запустился, мы всё сделали правильно, настройка сервера закончена.

Действие второе. Удаление лишнего из мода:

Открываем наш мод. Первое что бросается нам в глаза, это

#if defined FILTERSCRIPT

public OnFilterScriptInit()
{
	print("n--------------------------------------");
	print(" Blank Filterscript by your name here");
	print("--------------------------------------n");
	return 1;
}

public OnFilterScriptExit()
{
	return 1;
}

#else

main()
{
	print("n----------------------------------");
	print(" Blank Gamemode by your name here");
	print("----------------------------------n");
}

#endif

Вот это нам не нужно. Удаляем.
Находим паблик

public OnGameModeInit()
{
	SetGameModeText("Blank Script");
	AddPlayerClass(0, 1958.3783, 1343.1572, 15.3746, 269.1425, 0, 0, 0, 0, 0, 0);
	return 1;
}

И после него, вставляем

main()
{
	print("n----------------------------------");
	print(" Название вашего мода, у меня будет pawn-wiki");
	print("----------------------------------n");
}

В самом начале мода, мы можем видеть такую строку.

#include <a_samp>

Если подумать головой, то можно понять что это подгрузка инклудов в мод. После него добавим наш инклуд:

#include <mxINI>

Нажимаем F5, и компилируем мод, если всё прошло без ошибок, значит вы всё сделали правильно.

Находим строку

SetGameModeText("Blank Script");

Эта строка, устанавливает название мода, которое будет видно в клиенте. Меняем его на своё.

SetGameModeText("Pawn-wiki Mode");

Компилируем мод, и.. мы закончили с подготовкой мода. Теперь нас ждёт система регистрации.

Действие Третье. Сохранение аккаунта.

Переходим к созданию того, чем мы будет пользоваться постоянно. Это данные о аккаунте.
После строки с добавлением нашего инклуда, создаём масив, с информацией о игроке.

enum pInfo
{
	pPass[64],// Масив с паролем
}
new Player[MAX_PLAYERS][pInfo];

Теперь мы можем записать пароль, определённого игрока, чем мы сейчас и займёмся.

Опускаемся в самый конец мода, и создаём там, вот это:

stock SavePlayer(playerid)
{
    new string[64];// Масив с путём для файла
	new playername[MAX_PLAYER_NAME];// Масив для получения имени игрока
	GetPlayerName(playerid, playername, sizeof(playername));// Получаем Имя игрока
	format(string, sizeof(string), "players/%s.ini", playername);// Добавляем имя игрока, в путь для сохранения
	iniFile = ini_openFile(string);// Открываем файл по тому пути который указали.
	ini_setString(iniFile, "Pass", Player[playerid][pPass]);// Записываем пароль игрока в файл
	ini_closeFile(iniFile);// Закрываем файл
}

Нажимаем F5, и мод компилируется. Если ошибок нет, то вы сделали всё правильно.
Теперь нам надо зайти в папку с сервером, открыть папку scriptfiles, и в ней добавить папку players.
Сохранение готово.

Действие Четвёртое. Создание регистрации и загрузки игрока.

Для создания регистрации, надо узнать, есть ли игрок с таким именем на сервере, для начала нужно после объявления нашего инклуда, вставить следующее:

new PAccount[MAX_PLAYERS];// Есть аккаунт, или нет

Далее ищем паблик OnPlayerConnect. И в него добавляем:

new playername[MAX_PLAYER_NAME];// Масив для имени игрока
new string[128];// Путь до папки с именем игрока
GetPlayerName(playerid,playername,sizeof(playername));// Узнаём имя игрока
format(string,sizeof(string),"players/%s.ini", playername);// Путь к файлу с аккаунтом
if(fexist(string))// Проверка на файл, если он есть то выполняется следующее действие.
{
	PAccount[playerid] = 1;// Аккаунт есть
}
else// Если файла с именем нет, то выполняется это действие.
{
	PAccount[playerid] = 0;// Аккаунта нет
}

Теперь ищем паблик, OnPlayerRequestClass, он покажет нам диалог с логином, или регистрацией, в него добавляем.

if(PAccount[playerid] == 1)// Если аккаунт есть
{
	ShowPlayerDialog(playerid,1,DIALOG_STYLE_INPUT,"Окно Входа","ЗдравствуйтеnВаш аккаунт есть на сервереnВведите свой пароль в окошко","Ввод","");// Показываем диалог входа в игру. Стиль диалога выставляем на ввод текста.
}
else// Если аккаунта нет
{
	ShowPlayerDialog(playerid,2,DIALOG_STYLE_INPUT,"Окно Регистрации","ЗдравствуйтеnВаш аккаунт не найден.nЗарегистрируйтесь введя пароль в окошко","Ввод","");// Показываем диалог регистрации. Стиль диалога выставляем на ввод текста.
}

Диалоги мы показали, но теперь надо заставить его работать. Для этого нам надо сделать функцию загрузки и регистрации игрока.
Этим мы и займёмся. В конец мода, вставляем.

forward OnPlayerRegister(playerid, password[]);
public OnPlayerRegister(playerid, password[])// Паблик регистрации
{
	if(IsPlayerConnected(playerid))
	{
	    new string[64];// Масив с путём для файла
		new playername[MAX_PLAYER_NAME];// Масив для получения имени игрока
		GetPlayerName(playerid, playername, sizeof(playername));// Получаем Имя игрока
		format(string,sizeof(string), "players/%s.ini", playername);// Добавляем имя игрока, в путь для сохранения
		new iniFile = ini_createFile(string);// Создаём файл с именем игрока в папке players
		if(iniFile < 0)// Если Файла нет
		{
			iniFile = ini_openFile(string);// Открываем
		}
		if(iniFile >= 0)// Если файл есть
		{
			strmid(Player[playerid][pPass],password,0,strlen(password),255);// Присваиваем масиву pPass, значение password[]
			ini_setString(iniFile,"Pass",Player[playerid][pPass]);// Записываем пароль игрока в файл
			ini_closeFile(iniFile);// Закрываем файл
			ShowPlayerDialog(playerid,1,DIALOG_STYLE_INPUT,"Окно Входа","ЗдравствуйтеnВаш аккаунт есть на сервереnВведите свой пароль в окошко","Ввод","");// Показываем диалог входа в игру.
		}
	}
	return 1;
}

Функция которая зарегистрирует игрока, готова, теперь функция логина. В конец мода, добавляем.

forward OnPlayerLogin(playerid,password[]);
public OnPlayerLogin(playerid,password[])
{
	if(IsPlayerConnected(playerid))// Проверка на подключение игрока
	{
     	new string[64];// Масив с путём для файла
     	new pass[64];// Масив с паролем
		new playername[MAX_PLAYER_NAME];// Масив для получения имени игрока
		GetPlayerName(playerid, playername, sizeof(playername));// Получаем Имя игрока
		format(string,sizeof(string), "players/%s.ini", playername);// Добавляем имя игрока, в путь для загрузки
		new iniFile = ini_openFile(string);// Открываем файл
  		ini_getString(iniFile,"Pass",pass,64);// Загружаем пароль
    	if(strcmp(pass,password,true) == 0)// Если введёный пароль, соответсвует паролю при регистрации, то загружаем акк
	    {
     		ini_getString(iniFile,"Pass",Player[playerid][pPass],64);// Загружаем пароль
     		ini_closeFile(iniFile);// Закрываем файл
    	}
		else// Если пароль не верен..
		{
		    ini_closeFile(iniFile);// Закрываем файл
	    	ShowPlayerDialog(playerid,1,DIALOG_STYLE_INPUT,"Окно Входа","ЗдравствуйтеnВаш аккаунт есть на сервереnВведите свой пароль в окошко","Ввод","");// Показываем диалог входа в игру.
	    	return 1;
		}
		SendClientMessage(playerid,0xFF00000,"Добро пожаловать на наш сервер");// Выводим игрок сообщение
		SpawnPlayer(playerid);// Спавним игрока
	}
	return 1;
}

Функция регистрации есть, логина есть, осталось заставить их работать, для этого находим паблик OnDialogResponse и вставляем в него:

if(dialogid == 1)// Ид диалога Для Логина
{
	if(response)// Если игрок нажал первую кнопку входа
	{
		if(!strlen(inputtext))// Если окно ввода пустое, выводим диалог снова
		{
			ShowPlayerDialog(playerid,1,DIALOG_STYLE_INPUT,"Окно Входа","ЗдравствуйтеnВаш аккаунт есть на сервереnВведите свой пароль в окошко","Ввод","");// Показываем диалог входа в игру.
			return 1;
		}
		new pass[64];// Масив с паролем
		strmid(pass,inputtext,0,strlen(inputtext),64);// Считываем текст с диалога
		OnPlayerLogin(playerid,pass);// Запускаем паблик входа
	}
	else// Если игрок нажал Esc, вернём ему диалог
	{
		ShowPlayerDialog(playerid,1,DIALOG_STYLE_INPUT,"Окно Входа","ЗдравствуйтеnВаш аккаунт есть на сервереnВведите свой пароль в окошко","Ввод","");// Показываем диалог входа в игру.
	}
}
if(dialogid == 2)// Ид диалога для регистрации
{
	if(response)// Если игрок нажал первую кнопку 
	{
		if(!strlen(inputtext))// Если окно ввода пустое, выводим диалог снова
		{
			ShowPlayerDialog(playerid,2,DIALOG_STYLE_INPUT,"Окно Регистрации","ЗдравствуйтеnВаш аккаунт не найден.nЗарегистрируйтесь введя пароль в окошко","Ввод","");// Показываем диалог регистрации.
			return 1;
		}
		new pass[64];// Масив с паролем
		strmid(pass,inputtext,0,strlen(inputtext),64);// Считываем текст с диалога
		OnPlayerRegister(playerid,pass);// Запускаем паблик регистрации
	}
	else// Если игрок нажал Esc, вернём ему диалог
	{
		ShowPlayerDialog(playerid,2,DIALOG_STYLE_INPUT,"Окно Регистрации","ЗдравствуйтеnВаш аккаунт не найден.nЗарегистрируйтесь введя пароль в окошко","Ввод","");// Показываем диалог регистрации.
	}
}

Конец первой части.
Полезные ссылки:

— Include mxINI

new.rar
[1,84К]

Приношу свои извинения за ошибки в тексте.
Понравился урок? Пользуйся на здоровье.
Следующий урок, в ближайшие дни.
Автор урока: Vovan228

Глава I. Файлы, программы нужные нам

Для начала нам понадобится сам сервер. ( http://files.sa-mp.com/samp03z_svr_R1_win32.zip )
Распаковываем все содержимое архива в удобную нам папку.
Далее открываем файл server.cfg (блокнотом) и меняем нужные нам данные на свои, а именно:

Код: Выделить всё

echo Executing Server Config... 
lanmode 0 
// Не меняем! 
rcon_password changeme // Обязательно меняем, или сервер не запустится 
maxplayers 50 // Меняем на свое значение ( максимальное кол-во игроков, до 500 ) 
port 7777 // Порт ( по умолчанию 7777 ) 
hostname SA-MP 0.3 Server // Название сервера 
gamemode0 grandlarc 1 // Название мода, меняем на своё ( У нас это будет new.pwn, Значит меняем grandlarc на new ) 
filterscripts gl_actions gl_realtime gl_property gl_mapicon ls_mall attachments skinchanger vspawner // Удаляем: gl_actions gl_realtime gl_property gl_mapicon ls_mall attachments skinchanger vspawner 
announce 0 // Не меняем 
query 1 // Не меняем 
chatlogging 0 // Не меняем 
weburl www.sa-mp.com // Web-адресс сервера 
onfoot_rate 40 // Не меняем 
incar_rate 40 // Не меняем 
weapon_rate 40 // Не меняем 
stream_distance 300.0 // Не меняем 
stream_rate 1000 // Не меняем 
maxnpc 0 // Не меняем 
logtimeformat [%H:%M:%S] // Не меняем     

Поменяли? Но это ещё не все, приписываем ко всему строку:

— Это плагины, объясню позже
У нас получиться что-то вроде этого:

Код: Выделить всё

echo Executing Server Config... 
lanmode 0 
rcon_password 12345  
maxplayers 500 
port 7777 
hostname New RP 
| Client: 0.3x 
gamemode0 new 1 
filterscripts  
announce 0 
query 1 
chatlogging 0 
weburl www
. 
onfoot_rate 40 
incar_rate 40 
weapon_rate 40 
stream_distance 300.0 
stream_rate 1000 
maxnpc 0 
logtimeformat 
[%H:%M:%S] 
plugins streamer mysql

И так, если вы хотите чтобы ваш мод работал правильно, то вам следующие плагины:

Стример
1. Streamer.inc, который лежит в папке pawno/include закидываем к себе в папку pawno/include вашего сервера.
2. Streamer.dll, который лежит в папке plugins закидываем в папку plugins вашего сервера. Примечание: Если сервер находиться на оси Linux, то закидываем Streamer.so, в server.cfg все плагины должны быть написаны с расширением .so.
Например: Streamer.so
Ну все. Нам нужны только эти два файла.
MySQL R39-2 — Мы будем использовать плагин R39-2
1. a_mysql.inc закидываем к себе в папку pawno/include вашего сервера.
2. mysql.dll закидываем в папку plugins вашего сервера.
3. libmysql.dll обязательно кидаем в папку с сервером
Денвер — И самое главное, это Denwer (Denwer обеспечит нам Базу Данных MySQL PhpMyAdmin).
Устанавливаем Denwer. Думаю, вопросы по его установке не возникнут.

Глава II. Начинаем работу

И так, установили Denwer, закинули плагины? Тогда поехали.

Для начала заходим в папку своего сервера, видим там другую папку «pawno«, заходим в неё. Далее заходим в саму программу pawno.exe Давайте начнем писать наш мод. Нажмем на самую первую иконку «New«. Мы создали новый мод, если мы сохраним его под названием «new» в папку «gamemodes» запустим сервер и зайдем на него ( для захода используйте IP: 127.0.0.1 ), то увидим всем знакомого негра CJ в районе Лас Вентураса, как мы видим это ещё не совсем Role Play мод, так давайте его уже наконец начнем делать! Идем в pawno и начинаем работу. Для начала давайте впишем наши инклуды таким образом:
После строки:

Вставляем:

Для начала давайте удалим ненужные нам строки:

Код: Выделить всё

#if defined FILTERSCRIPT 
 
public OnFilterScriptInit
() 
{ 
    print
("n--------------------------------------"); 
    print
(" Blank Filterscript by your name here"); 
    print
("--------------------------------------n"); 
    return 1
; 
} 

 public OnFilterScriptExit

() 
{ 
    return 1
; 
} #else     

Далее заменим:

Код: Выделить всё

main() 
{ 
    print
("n----------------------------------"); 
    print
(" Blank Gamemode by your name here"); 
    print
("----------------------------------n"); 

На:

Код: Выделить всё

main()
{
    if(mysql_errno())
        printf(" Подключение к базе `%s` не успешно", mysql_db);
    else
        printf
(" Подключение к базе `%s` успешно", mysql_db);

Кстати немного о main().
Как вы видите функция print при запуске мода покажет нам текст в консоле который мы с вами ввели. Вы можете добавить ещё полей и написать в них что угодно. Так-же функция print служит для поиска багов в моде. Например у вас не работает функция, постепенно вставляйте print в код
Пример: (при проверке рекомендую использовать print)

Код: Выделить всё

stock Some_Function(playerid) 
{ 
    print
("Проверяем подключен ли игрок"); 
    if
(IsPlayerConnected(playerid)) // Если игрок подключен,то 
    { 
        printr
("Проверку прошли, ставим погоду"); 
        SetPlayerWeather
(playerid, 10);// Выводим ему погоду id 10 
        print("Паблик успешно выполнен"); 
    
}

Немного истории…
При написании мода используются различные символы и переменные, разберем их.

Код: Выделить всё

|| - это означает "или", пример PlayerInfo[playerid][pLeader] == 1 || PlayerInfo[playerid][pMember] == 1 ( Рабочий фракции 1 или лидер фракции 1) 
&& - это означает "и", пример PlayerInfo[playerid][pMember] == 1 && PlayerInfo[playerid][pRank] == 3 ( Рабочий фракции 1 и у него 3 ранг ) 
! - это означает "не", пример (!IsPlayerConnected) ( игрок не подключен ) 
if 
- это означает "если", пример  
if 
(!IsPlayerConnected) 
{ 
if PlayerInfo
[playerid][pMember] == 1 && PlayerInfo[playerid][pRank] == 3; и так далее 
else 
- это означает "иначе" , также бывает выражение "else if" - иначе если

Но вернемся к моду И так, удаляем строку:

Удалили? Отлично, перейдем к разборке самого мода.

Давайте для начала пропишем данные к базе MySQL, для этого отступаем одну строку после инклудов и пишем следующее:

Код: Выделить всё

#define mysql_host "localhost" // если запускаем сервер у себя на компьютере, то оставляем 
#define mysql_db "samp" // имя базы данных mysql 
#define mysql_user "root" // пользователь Mysql 
#define mysql_pass "" // пароль от mysql     

Далее давайте отступим ещё одну строчку и вставим следующую строку:

Также отступаем одну строку и вставляем:

Код: Выделить всё

enum pInfo  
{  
    Key
[128],//переменная пароля  
    Level //уровень игрока 
};  
new PlayerInfo
[MAX_PLAYERS][pInfo]; 

Далее идем чуть ниже,в public OnGameModeInit() и вставляем туда следующее:

Код: Выделить всё

mysql_variable = mysql_connect(mysql_host, mysql_user, mysql_db, mysql_pass);
SetGameModeText("Register R39-2"); 

В итоге у нас получится такой паблик (public):

Код: Выделить всё

public OnGameModeInit()
{
    mysql_variable = mysql_connect(mysql_host, mysql_user, mysql_db, mysql_pass);
    SetGameModeText("Register R39-2");
    AddPlayerClass(0, 1958.3783, 1343.1572, 15.3746, 269.1425, 0, 0, 0, 0, 0, 0);
    return 1;

Далее таким же образом вставляем следующее в public OnGameModeExit():

В public OnPlayerConnect(playerid):

Код: Выделить всё

static const
    str
[] = "SELECT `Name` FROM `Accounts` WHERE `Name` = '%s'";

const

    size = sizeof(str)-2+MAX_PLAYER_NAME;

new

    string[size];mysql_real_escape_string(Name(playerid), Name(playerid));
format(string, sizeof(string), str, Name(playerid));
mysql_function_query(mysql_variable, string, true, "OnPlayerRegCheck", "d", playerid); 

В public OnPlayerText(playerid, text[]):

Код: Выделить всё

if(!GetPVarInt(playerid, "Logged"))
    return !SendClientMessage(playerid, -1, "Что бы писать в чат, нужно быть авторизированым."); 

В public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[]):

Код: Выделить всё

switch(dialogid)
{
    case 1://Регистрация
    {
        if(inputtext[0] == '')
            return ShowPlayerDialog(playerid,1,DIALOG_STYLE_INPUT,"Регистрация","Добро пожаловать на сервер!nВаш аккаунт не зарегистрирован!nnВведите пароль:","Далее","Отмена");
        OnPlayerRegister(playerid, inputtext);
        return 1;
    }
    case 2://Авторизация
        {
        if(inputtext[0] == '')
            return ShowPlayerDialog(playerid,2,DIALOG_STYLE_PASSWORD,"Авторизация","Здравствуйте!nnВы зарегистрированы!nВведите пароль:","Вход","Отмена");
        OnPlayerLogin(playerid, inputtext);
        return 1;
    }

В самый конец кода:

Код: Выделить всё

stock OnPlayerRegister(p, password[])
{
       static const
        str
[] = "INSERT INTO `Accounts` (`Name`, `Key`) VALUES ('%s', '%s')";    const
        size 
= sizeof(str)-2+MAX_PLAYER_NAME-2+128;
      
    new
        string
[size];
    
    format
(string, sizeof(string), str, Name(p), password);
    mysql_function_query(mysql_variable, string, false, "RegisterCallback", "d", p);
    return 1;
}
 
public RegisterCallback
(playerid);
public RegisterCallback(playerid)
{
    SendClientMessage(playerid, -1, "Вы успешно зарегистрировались!");
    SetPVarInt(playerid,"Logged", 1);
    SpawnPlayer(playerid);
    return 1;
}
 
SavePlayer
(p)
{
    if(GetPVarInt(p,"Logged") > 0)
    {
        static const
            str0
[] = "UPDATE `Accounts` SET `Key`, `Level` = '%d'",
            str1[] = "%s WHERE `Name` = '%s'";
        
        const
            size0 
= sizeof(str0)-2+128-2+16,
            size1 = sizeof(str1)-2+128-2+MAX_PLAYER_NAME;        #if    size0>size1
            #define    size size0
        #else
            #define size size1
        #endif
        new
            string
[size];
        
        format
(string, sizeof(string), str0, PlayerInfo[p][Key], PlayerInfo[p][Level]);
        format(string, sizeof(string), str1, string, Name(p));
        mysql_query(mysql_variable, string, false);
    }
    return 1;
}
 
stock OnPlayerLogin
(i, password[])
{
       static const
        str
[] ="SELECT * FROM `Accounts` WHERE `Name` = '%s' AND `Key` = '%s'";    const
        size 
= sizeof(str)-2+MAX_PLAYER_NAME-2+128;    new
        string
[size];
    
    format
(string, sizeof(string),str, Name(i), password);
    mysql_function_query(mysql_variable, string, true, "LoginCallback", "ds", i, password);
    return 1;
}
 
public LoginCallback
(i, password[]);
public LoginCallback(i, password[])
{
    static const
        str
[] = "Вы ввели неверный пароль ( попыток: %i/ 3 )";
    
    new
        rows
,
        fields,
        maximum[128],
        string[sizeof(str)-2+1];
    
    cache_get_data
(rows, fields);
    if(!rows)
    {
        if(GetPVarInt(i, "wrongPass") == 2)
            return SendClientMessage(i, -1, "Вы ввели неверный пароль уже 3 раза. Вы кикнуты."), Kick(i);        SetPVarInt(i, "wrongPass", GetPVarInt(i, "wrongPass") + 1);
        format(string, sizeof(string),str, 3 - GetPVarInt(i, "wrongPass"));
        ShowPlayerDialog(i, 2, DIALOG_STYLE_PASSWORD, "Авторизация", string, "Вход", "Выход");
        return 1;
    }
    cache_get_field_content(0, "Level", maximum), PlayerInfo[i][Level] = strval(maximum);
    SetPVarInt(i, "Logged", 1);
    SendClientMessage(i, -1, "Вы успешно авторизовались!");
    SpawnPlayer(i);
    SavePlayer(i);
    return 1;

Этим этапом мы с вами сделали регистрацию, и авторизацию на сервере. Спасибо Jeff_Hardy за данные коды по регистрации и авторизации.
Но это ещё не все, давайте запустим наш Denwer, далее в адресной строке наберем следующую ссылку: http://localhost/Tools/phpMyAdmin/
Создадим нашу Базу Данных samp и зайдем в неё, зайдя в неё мы с вами увидим сверху вкладочку «SQL» или «Структура», жмем на неё.
В появившемся поле мы вставим следующий код:

Код: Выделить всё

CREATE TABLE IF NOT EXISTS `Accounts`
(
  
    
`Name` varchar(24) COLLATE cp1251_bin NOT NULL,  
    
`Key` varchar(30) CHARACTER SET utf8 NOT NULL,  
    
`Level` int(3) NOT NULL  
)
ENGINE=MyISA

Все готово! Теперь мы можем скомпилировать мод (F5) и запустить его.
Автор: Pro-Pawn Team
Исходники: Мод

// This is a comment
// uncomment the line below if you want to write a filterscript
//#define FILTERSCRIPT

#include <a_samp>

#if defined FILTERSCRIPT

public OnFilterScriptInit()
{
print(«n—————————————«);
print(» Blank Filterscript by your name here»);
print(«—————————————n»);
return 1;
}

public OnFilterScriptExit()
{
return 1;
}

#else

main()
{
print(«n———————————-«);
print(» Blank Gamemode by your name here»);
print(«———————————-n»);
}

#endif

public OnGameModeInit()
{
// Don’t use these lines if it’s a filterscript
SetGameModeText(«Blank Script»);
AddPlayerClass(0, 1958.3783, 1343.1572, 15.3746, 269.1425, 0, 0, 0, 0, 0, 0);
return 1;
}

public OnGameModeExit()
{
return 1;
}

public OnPlayerRequestClass(playerid, classid)
{
SetPlayerPos(playerid, 1958.3783, 1343.1572, 15.3746);
SetPlayerCameraPos(playerid, 1958.3783, 1343.1572, 15.3746);
SetPlayerCameraLookAt(playerid, 1958.3783, 1343.1572, 15.3746);
return 1;
}

public OnPlayerConnect(playerid)
{
return 1;
}

public OnPlayerDisconnect(playerid, reason)
{
return 1;
}

public OnPlayerSpawn(playerid)
{
return 1;
}

public OnPlayerDeath(playerid, killerid, reason)
{
return 1;
}

public OnVehicleSpawn(vehicleid)
{
return 1;
}

public OnVehicleDeath(vehicleid, killerid)
{
return 1;
}

public OnPlayerText(playerid, text[])
{
return 1;
}

public OnPlayerCommandText(playerid, cmdtext[])
{
if (strcmp(«/mycommand», cmdtext, true, 10) == 0)
{
// Do something here
return 1;
}
return 0;
}

public OnPlayerEnterVehicle(playerid, vehicleid, ispassenger)
{
return 1;
}

public OnPlayerExitVehicle(playerid, vehicleid)
{
return 1;
}

public OnPlayerStateChange(playerid, newstate, oldstate)
{
return 1;
}

public OnPlayerEnterCheckpoint(playerid)
{
return 1;
}

public OnPlayerLeaveCheckpoint(playerid)
{
return 1;
}

public OnPlayerEnterRaceCheckpoint(playerid)
{
return 1;
}

public OnPlayerLeaveRaceCheckpoint(playerid)
{
return 1;
}

public OnRconCommand(cmd[])
{
return 1;
}

public OnPlayerRequestSpawn(playerid)
{
return 1;
}

public OnObjectMoved(objectid)
{
return 1;
}

public OnPlayerObjectMoved(playerid, objectid)
{
return 1;
}

public OnPlayerPickUpPickup(playerid, pickupid)
{
return 1;
}

public OnVehicleMod(playerid, vehicleid, componentid)
{
return 1;
}

public OnVehiclePaintjob(playerid, vehicleid, paintjobid)
{
return 1;
}

public OnVehicleRespray(playerid, vehicleid, color1, color2)
{
return 1;
}

public OnPlayerSelectedMenuRow(playerid, row)
{
return 1;
}

public OnPlayerExitedMenu(playerid)
{
return 1;
}

public OnPlayerInteriorChange(playerid, newinteriorid, oldinteriorid)
{
return 1;
}

public OnPlayerKeyStateChange(playerid, newkeys, oldkeys)
{
return 1;
}

public OnRconLoginAttempt(ip[], password[], success)
{
return 1;
}

public OnPlayerUpdate(playerid)
{
return 1;
}

public OnPlayerStreamIn(playerid, forplayerid)
{
return 1;
}

public OnPlayerStreamOut(playerid, forplayerid)
{
return 1;
}

public OnVehicleStreamIn(vehicleid, forplayerid)
{
return 1;
}

public OnVehicleStreamOut(vehicleid, forplayerid)
{
return 1;
}

public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
return 1;
}

public OnPlayerClickPlayer(playerid, clickedplayerid, source)
{
return 1;
}

eef9013c237061ce32f422822ee14186.jpg

О остальных девяти кнопках, я расскажу позже.

2) Всё, скрипт мы создали, начинаем чистить его.

Удаляем:

// This is a comment
// uncomment the line below if you want to write a filterscript
//#define FILTERSCRIPT

Код:

#if defined FILTERSCRIPT

public OnFilterScriptInit()
{
	print("n--------------------------------------");
	print(" Blank Filterscript by your name here");
	print("--------------------------------------n");
	return 1;
}

public OnFilterScriptExit()
{
	return 1;
}

#else

Переходим в паблик OnPlayerRequestClass и удаляем:

SetPlayerPos(playerid, 1958.3783, 1343.1572, 15.3746);
SetPlayerCameraPos(playerid, 1958.3783, 1343.1572, 15.3746);
SetPlayerCameraLookAt(playerid, 1958.3783, 1343.1572, 15.3746);

Переходим в паблик OnPlayerCommandText и удаляем:

if (strcmp(«/mycommand», cmdtext, true, 10) == 0)
{
// Do something here
return 1;
}

В будущем, с этим пабликом мы работать не будем, т.к. командный процессор будет DC_CMD.

Прописываем необходимые функции, и настраиваем мод.

Всё, мод мы подчистили, теперь пора настроить сердечко нашего мода.

1) Переходим в паблик OnGameModeInit и добавляем:

DisableInteriorEnterExits();

Эта функция отключает все входы/выходы зданий (желтые маркеры).

EnableStuntBonusForAll(0);

Включает/отключает начисление денег за совершенные трюки (работает для всех игроков). Если включено, игроки будут получать денежное вознаграждение при выполнении трюков на транспортном средстве.

LimitPlayerMarkerRadius(100.0);

Функция определяет, на каком расстоянии будет виден клист игрока.

2) С функциями мы закончили, теперь настроим мод. Пока что, мы будем настраивать только одну функцию.

Переходим в паблик OnGameModeInit. Видим строчку:

SetGameModeText(«Blank Script»);

Где «Blank Script» — это название вашего мода, его Вы можете изменить (главное не удаляйте кавычки :D83DDE0F: ).

Теперь нам нужно скомпилировать мод. Для чего это нужно? Как правило: .pwn файл — это исходник, который мы редактируем, и с которым мы работаем сейчас; .amx — это исполняющий файл, который требуется для работоспособности сервера. Т.е. если мы не скомпилируем мод, то сервер работать не будет, т.к. мы не преобразовали .amx(исполняющий) файл из .pwn файла(исходник). Для того чтобы скомпилировать мод, жмём восьмую кнопку(«Compile», скриншот ниже), перед вами появляется окно. Путь выбираем: папка с сервером &gt; gamemodes. Имя вводим: new.

fe6388fc00f69ad1fe485a325f7f366a.jpg

На этом всё!

Полезные ссылки:

  • New.pwn

Урок подготовил: TheSeLToN.

Всем огромное спасибо за внимание!

Цитата Nazar_Conors ()

Ребятки, вообщето я здесь собрался писать сразу с Text Draw, тоесть не на диалогах всё.
Ктому же версия 0.3.7, еще нету уроков на подобе вот этого.
Если вы не хотите, это не значит что другие не хотят.

А, собственно, где тут отличие от предыдущих версий? Правильно, их нет.
Даже разработчик сампика это подтверждает:

Цитата

— Over 500 new object IDs added, including stunt objects and land objects.
— Interface font size changing.
— Some new variations of the San Andreas cop skins.
— Server control of the car doors and windows.
— The ability to add sirens for unmarked cop cars.
— A simple static actor system to more easily create actor NPCs for shops.
— Many bug fixes and new scripting features.

Я просто тебе выскажу мнение, как человек, который в pawn ушел не намного дальше среднестатистического хелловордера:
Это муть. Стоит рассматривать что-то более существенное, чем разбор интуитивно понятного файла человеку, который хоть чуть чуть владеет логикой и англ.языком.
Давай что то посущественнее и более объёмно, чтоль. Ябпочитал.

В данном уроке мы сделаем шаблон для нашего первого плагина.

Первое что нам понадобится, это Visual Studio с установленными c++ дополнениями, а так же SDK

Установив все самое нужное, можно приступать к созданию проекта

1. Открываем Visual Studio

2. Справа жмем создание проекта

605f7a0e94675_.png.489f455b0f2d0da4a671691787f64529.png

3. Выбираем Библиотека Динамической компоновки ( DLL )

605f7a3966613_.png.30af518848104d9336f0124a5e796b0b.png

4. Указываем любое название проекта

605f7aa674acc_.png.37a126ed8268e394f7aff0edb6742b62.png

5. Создав проект, выбираем в самом верху Release, x86 ( SA:MP 32 битный ) 

605f7b2a6c0bc_.png.b185c009ed94574b7d5bcbf4ba6dbb6a.png

6. Открываем нашу папку с проектом и разархивируем SDK.zip

7. Включаем отображение всех файлов

605f7cb14285b_.png.e4f2a1f6ee91fd3e317d768693bfc996.png

8. У нас должна появиться папка SDK, жмем по ней правой кнопкой мыши и включаем в проект

9. Отключаем отображение файлов

10. Создаем plugin.def (для экспорта определения модулей)

Жмем правой кнопкой мыши по нашему проекту -> добавить -> создать элемент

605f7e237e8ff_.thumb.png.3d452c270ed38efafcb50f6b83d381c6.png

11. Выбираем Visual C++ -> Код -> Файл определения модуля ( .def )

605f7e79a1b1a_.png.d58fe559276d569566cdd51bd5ff8734.png

11. Жмем правой кнопкой мыши по проекту -> свойства -> компоновщик -> ввод -> пишем «plugin.def»

605f7ed8004b6_.png.0ed2d8b915005989ab87de362a4b303a.png

12. Открываем dllmain.cpp и вставляем следующий код:

#include "SDK/amx/amx.h"
#include "SDK/plugincommon.h"

extern void *pAMXFunctions;
void *(*logprintf)(const char *fmt, ...);

PLUGIN_EXPORT unsigned int PLUGIN_CALL Supports()
{
	return SUPPORTS_VERSION | SUPPORTS_AMX_NATIVES;
}

PLUGIN_EXPORT bool PLUGIN_CALL Load(void **ppData)
{
	pAMXFunctions = ppData[PLUGIN_DATA_AMX_EXPORTS];
	logprintf = (void *(*)(const char *fmt, ...))ppData[PLUGIN_DATA_LOGPRINTF];
	
	if (NULL == pAMXFunctions || NULL == logprintf)
		return false;

	logprintf("  clear plugin loaded..");
	return true;
}

PLUGIN_EXPORT void PLUGIN_CALL Unload()
{
	logprintf("  clear plugin unloaded..");
}

13 Жмем правой кнопкой мыши по проекту -> собрать

Если сделали все правильно, в выводе должно быть написано следующее:

605f7f548d049_.png.855c5358f4c2ae545d9fc45d952651ba.png

Копируем из папки Release к себе в папку plugins, прописываем в server.cfg и проверяем

605f7fbe18f8e_.png.5ecc10d56b925a20878ac95178e2e82d.png

Снизу предоставлен полный собранный проект.

Гайд об pawn и описание всех функций находится тут

SDK.zip

clearPlugin.zip

34 Kb

Любому игростроевцу, который захочет сделать мод для San Andreas, придется продираться через густые скриптовые заросли. Ведь с помощью скриптов можно изменить практически любую игровую составляющую. Хотите добавить в SA безбашенную мини-игру? Не вопрос. Желаете сделать собственный ролик на игровом движке или новую миссию? Тоже не проблема. Главное, научиться разбираться в принципах скриптописания.

Теорию и общие вопросы мы регулярно разбираем в “Самопале” (смотрите цикл статей “Игровое программирование”), на страницах же “Мастерской” займемся целенаправленным изучением скриптового языка конкретно GTA: SA.

Сегодня мы разберемся с основами языка программирования игры и научимся создавать несложные модификации. Самая популярная и распространенная программа для скриптинга под San Andreas — SAMB. Возможности этого редактора безграничны. Впрочем, нет, есть одно серьезное ограничение — ваша фантазия. Но тут мы вам, увы, не помощники. Зато разобраться в редакторе поможем легко. Забирайте SAMB с нашего диска и внемлите.

Важное отступление. При написании скриптов очень большое значение имеет количество пробелов, которое стоит между теми или иными элементами скрина. В статье для удобства восприятия везде стоит по одному пробелу, но если вы хотите, чтобы мод работал, число пробелов должно быть “правильным”. Для этого отправляйтесь на наш диск, где выложены исходные скрипты.

Первый запуск

Во время первого запуска редактора вам необходимо указать директорию с установленной игрой, после чего программа запустится автоматически (в ранних версиях редактора директорию указывать не нужно). Ознакомимся с интерфейсом программы.

Большую часть редактора занимает текстовое окно (пока оно серое), где мы и будем создавать что-то новое или редактировать уже существующее. Над этим окном располагается очень удобная панель инструментов. Откройте файл main.scm, располагающийся в подпапке игры: Data/Script — для этого в панели инструментов щелкните на значок папки со стрелочкой или зайдите в пункт меню File/Open. Перед вами появится подобие проводника Windows.

В правом окне вы должны указать путь к файлу main.scm. Например: C:GamesGtaSandatascript. После этого напротив поля File type выберите SCM-файлы. В результате в левом окне появится файл main.scm.

Щелкните по нему один раз и нажмите OK. Перед вами появится еще одно меню, в котором необходимо указать путь хранения файла (можно выбрать любой путь). Когда вы определитесь с местом хранения scm-файла, смело нажмите кнопку OK еще раз. Подождите несколько минут, пока программа переведет машинный код в читабельный язык программирования игры.

Синтаксис редактора

Ознакомимся с синтаксисом редактора. Если не соблюдать элементарные правила написания скриптов, то программа будет выдавать массу ошибок. Она просто не поймет, что вы хотите ей сказать.

Все миссии в GTA: SA представляют собой массу связанных между собой команд. Любая строка с необходимой командой, в свою очередь, состоит из трех частей, например 0417: start_mission $test.

35 Kb

Не горим и в воде не тонем!

Разберем эту строчку более подробно:

0417: — это код команды;

start_mission — сама команда, игнорируется редактором;

$test — переменная или число (числа).

Еще один пример: 03D8: show save screen. (03D8: — код команды; show save screen — команда).

Совсем не обязательно запоминать коды всех команд. В редактор встроена подсказка. Например, если вы напишите ключевое слово boat (лодка) и нажмете клавишу F1, программа автоматически подберет нужную команду:

02D3: boat $A88 drive to 171.0578 942.3843 6.0

Нажав клавишу F1 еще несколько раз, редактор будет подбирать коды команд с интересующим вас словом до тех пор, пока не закончатся все варианты. На слово boat будет выведено следующее:

02D3: boat $A88 drive to 171.0578 942.3843 6.0

02DB: set boat $A88 speed to 10.0

02D3: boat $A88 drive to 171.0578 942.3843 6.0

043a: start boat foam animation ;; never used in VC

043b: update boat $cutsceneanim foam animation ;; never used in SA

02D3: boat $A88 drive to 171.0578 942.3843 6.0

Чтобы посмотреть ключевые слова, как, например, в случае с лодкой, откройте документ Keywords, поставляющийся вместе с редактором.

Создание модификаций

Мы плавно подошли к самому ответственному моменту: созданию собственных модификаций. Для начала разберемся, из чего состоит файл любой миссий в San Andreas.

Файл main.scm состоит из четырех частей.

1 часть. Ставит размер памяти для скриптов — нужно только для редактора.

2 часть. Список используемых объектов в игре и скриптах.

3 часть. Указатели на миссии и внутриигровые блоки.

4 часть. Собственно код миссий, мини-игр, путей самолетов/вертолетов.

Пока нас не будут интересовать первые два блока — они не нужны, если вы не собираетесь создавать мегасложную миссию или совершенно новую игру.

Чтобы создать новую модификацию, нужно знать, как и с чего начать и чем закончить проект. Щелкните по “биноклю” в панели инструментов, в меню поиска введите 004F: create_thread ЈЈ и нажмите кнопку Find. Вы увидите список неизвестных пока вам команд. Давайте разберем на примере, как пишется мод.

004F: create_thread ЈЈIgromod1

004F: — это, как мы говорили чуть выше, код команды.

create_thread ЈЈ — это сама команда, отвечающая за создание потока, программы, ответственной за выполнение какого-либо действия, изменять команду нельзя!

Igromod1 — название нашего мода в файле main.scm.

52 Kb

Cj — настоящий медик. Хирург или патологоанатом…

Найдите то место, где заканчивается последняя команда, начинающаяся c 004F, и ниже вставьте свою строчку: 004F: create_thread ЈЈIgromod1;.

Обратите внимание, что символ ЈЈ необходимо копировать только из других команд: то, что вы напишете сами, программа не примет и выдаст ошибку при компиляции!

Далее в меню поиска (для быстрого вызова нажмите клавишу CTRL+F) введите слово orig и снова нажмите кнопку Find. Над строчкой:

;————-Mission 0—————

вы будете размещать все свои модификации, мини-игры, но не миссии — насчет этого будет отдельный разговор.

Любой блок, подпрограмма или мод начинается со строки Igromod1. Она играет роль идентификатора названия, которое вы писали выше. Название Igromod1 должно соответствовать названию Igromod1 в строке 004F: create_thread ЈЈIgromod1;.

Если названия не совпадут, то при компиляции — переводе языка программирования в машинный код игры — редактор снова выдаст ошибку, что блок не найден.

Ниже нужно написать строку с задержкой на определенное время, чтобы игра не зависла: 0001: wait 0 ms.

В моем случае задержка составила 0 мс, но если, например, вам нужно, чтобы какое-то действие выполнялось не сразу, то задержку можно увеличить.

Дальше начинается чистой воды эксперимент: Например, вы можете установить у игрока бесконечный бег:

0330: set player $PLAYER_CHAR infinite run to 1 (true)

Или сделать его (игрока, конечно) пожароустойчивым:

055D: make player $PLAYER_CHAR fireproof 1

А ведь можно и перекрашиваться совершенно бесплатно:

0335: set free paynspray to 1 (true)

Дадим игроку побольше денег — с ними в SA всегда были проблемы:

0109: player $PLAYER_CHAR money += 9000000

Вам мало брони и жизней — увеличим их стартовый набор на 100 единиц, мало не покажется:

035F: set_actor $PLAYER_ACTOR armour_to 100

055E: set_player $PLAYER_CHAR max_health += 100

Зачем ждать, пока нам в игре любезно предоставят реактивный ранец, создадим его около нашего дома (gRoove Famile Streets) сами!

032B: $jet = create_weapon_pickup 370 15 ammo 1 at 2488.562 -1666.864 12.8757

52 Kb

То, что вы должны увидеть при успешной декомпиляции скрипта.

Загадочные цифры 2488.562 -1666.864 12.8757 представляют собой координаты, по которым будет создан jetpack. О координатах и других непонятных цифрах в этой команде речь пойдет во второй статье цикла.

Думаю, быстрая перезарядка ствола придется всем по вкусу:

0331: unknown_player $PLAYER_CHAR set_fast_reload 1

Самое время научиться менять привычную одежку игрока. Изменить одежду главного героя на любую другую не так сложно. Для смены одежды игрока используются вместе две нижеуказанные команды:

087B: set_player $PLAYER_CHAR clothes «VEST» «VEST» 17

070D: $PLAYER_CHAR

Первая задает игроку определенную одежду, а вторая “обновляет” модельку персонажа.

Дадим игроку возможность рассекать по всему игровому миру без ограничений с самого начала игры:

0629: change_stat 181 (islands unlocked) to 4

И напоследок повысим скиллы персонажа до максимума:

062A: change_stat 165 (energy) to 999.0 ; float

062A: change_stat 23 (muscle) to 999.0 ; float

062A: change_stat 21 (fat) to 0.0 ; float

062A: change_stat 163 (health upgrade) to 999.0 ; float

062A: change_stat 160 (driving skill) to 999.0 ; float

062A: change_stat 229 (bike skill) to 999.0 ; float

062A: change_stat 223 (pilot skill) to 999.0 ; float

062A: change_stat 230 (cycling skill) to 999.0 ; float

Завершение проекта

Знаний для создания первого несложного мода вам уже хватит. Но чтобы модификация заработала, нужно еще написать команду, которая завершит работу после создания всех бонусных вещей. Выглядит она так: 004E: end thread.

49 Kb

Вид на наше творение из игры.

Если вы решили создать мод, содержащий все модификации, описанные в статье, то в итоге у вас должно получиться следующее:

:Igromod1

0001: wait 0 ms

0330: set player $PLAYER_CHAR infinite run to 1 (true)

055D: make player $PLAYER_CHAR fireproof 1

0335: set free paynspray to 1 (true)

032B: $jet = create_weapon_pickup 370 15 ammo 1 at 2488.562 -1666.864 12.8757

0109: player $PLAYER_CHAR money += 9000000

035F: set_actor $PLAYER_ACTOR armour_to 100

055E: set_player $PLAYER_CHAR max_health += 100

0629: change_stat 181 (islands unlocked) to 4

062A: change_stat 165 (energy) to 999.0 ; float

062A: change_stat 23 (muscle) to 999.0 ; float

062A: change_stat 21 (fat) to 0.0 ; float

062A: change_stat 163 (health upgrade) to 999.0 ; float

062A: change_stat 160 (driving skill) to 999.0 ; float

062A: change_stat 229 (bike skill) to 999.0 ; float

062A: change_stat 223 (pilot skill) to 999.0 ; float

062A: change_stat 230 (cycling skill) to 999.0 ; float

087B: set_player $PLAYER_CHAR clothes «countrytr» «countrytr» 17

070D: $PLAYER_CHAR

004E: end thread

Последние штрихи — нажмите клавишу F7, редактор скомпилирует файл в формат, привычный для игры. Скопируйте его из папки, в которой хранится main.scm (путь для хранения файла main.txt и будущего main.scm вы указывали во второй менюшке, появляющейся при открытии файла main.scm из директории Data/Script установленной игры) в папку Data/Script игры. После чего запускайте San Andreas — и можете играть в модификацию.

* * *

Мы изучили основы скриптового языка GTA: SA. Научились работать с редактором SAMB. Даже с этим базовым уровнем знаний вы уже можете экспериментировать, используя данные текстового файла Keywords.

Мы прощаемся с вами до следующей статьи (будет опубликована в одном из ближайших выпусков “Мастерской”), в которой наши модостроительные интересы значительно расширятся — мы научимся манипулировать персонажами и транспортными средствами, создавать свои видеоролики, познакомимся с понятием цикличности и освоим еще множество интереснейших возможностей.

Понравилась статья? Поделить с друзьями:
  • Как написать свой мессенджер на python
  • Как написать свой манифест
  • Как написать свой макрос на мышку
  • Как написать свой майнкрафт на java
  • Как написать свой майнер