• 0

Как сделать работу на моде копии радмира

Вопросы

Lemonoas
Новичок

Хочу сделать свою работу по моду чтобы работа работала, хочу сделать своими руками

Поделиться сообщением


Ссылка на сообщение

5 ответов на этот вопрос

  • 1
Cawfee
Великий Гуру

@Lemonoas, вопрос дюже общий, но давайте попробуем. И начать стоит с вопроса: "Что мы хотим?". Опишите детально, какую работу вы хотите реализовать, как вы это себе представляете, какой функционал требуется реализовать.

Поделиться сообщением


Ссылка на сообщение
  • 1
Cawfee
Великий Гуру

@Lemonoas, а что такое /bonusday?

 

Предлагаю идти поэтапно. Чтобы начать работу почтальона, потребуется какой-нибудь, пикап, наступление на который повлечет, скажем, появление диалогового окна с предложением начать работу и двумя кнопками: начать (если игрок еще не работает)/закончить (если игрок уже работает) и закрыть (для закрытия диалогового окна, отмена без изменения текущего состояния игрока).

 

1. Как создать пикап и обеспечить обработку события наступления на него?

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

При старте игрового сервера вызывается callback-функция OnGameModeInit - в ней, кроме всего прочего, вы можете порождать объекты, которые должны существовать на сервере во время его работы. В вашем случае таким объектом будет пикап, который создается через функцию CreatePickup. Функция имеет возвращаемое значение - идентификатор созданного пикапа - он потребуется для того, чтобы отслеживать, какой пикап активизировал игрок ( какой пикап он "подобрал"). Ваша задача - сохранить этот идентификатор в глобальную переменную (глобальной называю переменную, существующую в процессе работы сервера, область видимости которой ограничивается областью видимости по меньшей мере текущим файлом игрового мода). По большому счету делаете все то, что представлено в примере по вышеприведенной ссылке.

new gPostmanJobPickup; // глобальная переменная - вне всяких функций и процедур

public OnGameModeInit() {
    gPostmanJobPickup = CreatePickup(/* значения параметров - по вашему усмотрению */);
    return 1;
}

После выполнения этих действий на сервере вы должны увидеть созданный пикап с указанными вами внешним видом (моделью), типом, координатами.

 

Как только игрок "подбирает" этот пикап (фактически достаточно на него наступить), вызывается функция OnPlayerPickUpPickup, в которую в качестве параметров передаются ID игрока, подобравшего пикап, и номер пикапа, который им был подобран. Ваша задача - проверить внутри данной функции, какой пикап подобрал игрок (путем сверки идентификатора подобранного пикапа с идентификатором пикапа, созданного ранее). Если этот пикап связан с тем, что вы ранее создали, значит реализуем его обработку: отображаем игроку диалоговое окно.

public OnPlayerPickUpPickup(playerid, pickupid) {

    if (pickupid == gPostmanJobPickup) { // пикап работы почтальона
        // здесь уже логика, связанная с работой
        // выведем игроку текстовое сообщение - для проверки
        SendClientMessage(playerid, -1"Вы подобрали пикап почтальона");
    }

    return 1;
}

 

2. Начало работы почтальоном и ее завершение.

Как уже отметил выше, кнопки в диалоговом окне будут напрямую зависеть от того, работает уже игрок (значит нужно закончить работу) или нет (значит нужно начать работу). Для этого требуется создать переменную, которая бы хранила в себе информацию о том, какие игроки работают почтальонами, а какие - нет. Причем хранить нам требуется MAX_PLAYERS состояний (флагов), а значит созданию подлежит массив размером в MAX_PLAYERS ячеек, каждая ячейка которого будет соответствовать идентификатору игрока на сервере:

new gPostmans[MAX_PLAYERS]; // глобальная переменная
/*
    в ячейке gPostmans[0] хранится флажок, работает игрок с ID 0 почтальном (= 1) или нет (= 0)
    в ячейке gPostmans[1] хранится флажок, работает игрок с ID 1 почтальном (= 1) или нет (= 0)
    ...
    в ячейке gPostmans[511] хранится флажок, работает игрок с ID 511 почтальном (= 1) или нет (= 0)
*/

Поскольку по умолчанию все игроки не работают почтальонами, то по умолчанию все ячейки этой переменной должны иметь значение 0. На самом деле компиляторы при формировании машинного кода из исходных текстов программ обеспечивают инициализацию глобальных и статических переменных либо нулями (как значение по умолчанию). Однако, стоит рассмотреть следующую ситуацию. Вы запускаете сервер, все ячейки этой переменной имеют значение 0, а значит ни один игрок не работает почтальоном - все правильно и логично. Вы, имея идентификатор на сервере 0, начинаете работу почтальоном и получаете, соответственно, флажок 1, после чего выходите с сервера (по какой причине - неважно). Вы переподключаетесь к серверу (либо это делает другой игрок) и получаете идентификатор 0 (поскольку он был свободен). В то же время в массиве gPostmans все еще ячейка 0 имеет флажок 1. То есть игрок, зашедший на сервер, уже считается работающим почтальоном, что неверно. Следовательно, задача состоит в том, чтобы обеспечить сброс соответствующего значения ячейки игрокам, которые выходят с сервера.

Для отключившегося от сервера игрока вызывается функция OnPlayerDisconnect, из которой мы можем получать информацию о том, игрок с каким ID вышел с сервера. В теле данной функции сбрасываем флажок работы почтальоном:

public OnPlayerDisconnect(playerid, reason) {
    gPostmans[playerid] = 0// сбрасываем флажок работы почтальоном
}

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

Спойлер

public OnPlayerPickUpPickup(playerid, pickupid) {

    if (pickupid == gPostmanJobPickup) { // пикап работы почтальона
        if (gPostmans[playerid] == 0) { // если игрок еще не работает почтальоном
            // значит нужно предложить ему начать работу
            ShowPlayerDialog(
                playerid,
                0// идентификатор диалога - к этому мы еще вернемся позже
                DIALOG_STYLE_MSGBOX, // стиль диалога
                "Работа почтальоном"// название
                "Вы собираетесь начать работу почтальоном",
                "Начать"// левая кнопка в диалоговом окне
                "Закрыть" // правая кнопка в диалоговом окне
            );
        }
        else { // если игрок уже работает почтальоном
            // значит нужно предложить ему закончить работу
            ShowPlayerDialog(
                playerid,
                0// идентификатор диалога - к этому мы еще вернемся позже
                DIALOG_STYLE_MSGBOX, // стиль диалога
                "Работа почтальоном"// название
                "Вы собираетесь закончить работу почтальоном",
                "Закончить"// левая кнопка в диалоговом окне
                "Закрыть" // правая кнопка в диалоговом окне
            );
        }
    }

    return 1;
}

 

 

И, наконец, нужно реализовать обработку нажатия кнопок в диалоговом окне. Когда вы нажимаете какую-либо кнопку, вызывается функция OnDialogResponse. Ваша задача - проверить в ней, какой диалог был открыт (в соответствии с его номером) и какая кнопка (левая или правая) была нажата.

Спойлер

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

    if (dialogid == 0) { // если это диалоговое окно, связанное с работой почтальона
        if (!response) { // если игрок нажал правую кнопку (закрыть)
            // тогда ничего делать не нужно, диалоговое окно закроется само
            return 1;
        }

        // если игрок уже работает почтальоном
        if (gPostmans[playerid] == 1) {
            // значит он заканчивает работу, сбрасываем флажок
            gPostmans[playerid] = 0;
            // и дополнительно его проинформируем
            SendPlayerMessage(playerid, -1"Вы закончили работу почтальоном");
        }
        // если же игрок еще не работает почтальоном
        else {
            // значит он начинает работу, устанавливаем флажок
            gPostmans[playerid] = 1;
            // и дополнительно его проинформируем
            SendPlayerMessage(playerid, -1"Вы начали работу почтальоном");
        }

        return 1;
    }

    return 0;
}

 

 

На текущий момент я остановлюсь и предлагаю вам, во-первых, проверить работу данного фрагмента, во-вторых, реализовать свои действия по факту начала или завершения работы. Например, в начале работы вы можете игроку выдать какой-нибудь определенный скин, а в конце работы - вернуть игроку тот скин, что у него был. Для этого потребуется в начале работы сохранить родной скин игрока в ячейку нового массива (по аналогии с gPostmans).

 

Буду ждать ответ от вас.

Поделиться сообщением


Ссылка на сообщение
  • 0
Lemonoas
Новичок

хочу сделать работу почтальона, чтобы можно развозить посылки на машине любой патриот чтобы был функционал, и хотелось сделать /bonusday

 

Поделиться сообщением


Ссылка на сообщение
  • 0
Lemonoas
Новичок

@Cawfee спасибо огромное, этот код надо вставлять в конце кода?

 

Отредактировано пользователем Lemonoas

Поделиться сообщением


Ссылка на сообщение
  • 0
Cawfee
Великий Гуру

@Lemonoas, видимо, стоит поговорить о том, что вообще представляет собой игровой мод.

 

Все взаимодействие вашего игрового сервера с клиентом строится на основе функций обратного вызова (callback-функции) и нативных функций.

Посредством функций обратного вызова вы как разработчик можете получать информацию о возникших на сервере событиях: запуск игрового мода (OnGameModeInit), подключение игрока (OnPlayerConnect), его отключение (OnPlayerDisconnect), получение игроком урона (OnPlayerTakeDamage) и так далее (см. перечень функций обратного вызова здесь).

Нативные функции используются для того, чтобы выполнить на стороне сервере действие, направленное на какой-либо объект, реализованный разработчиком мультиплеера, например:

  • игровой мод (его перезапуск, останов);
  • фильтрскрипт (запуск, останов);
  • периферия (таймеры);
  • математические функции;
  • объекты карты (создание и удаление объектов маппинга, 3D-текстов, чекпоинтов, пикапов);
  • транспортные средства (создание и удаление транспортных средств, изменение их уровня здоровья, изменение цвета, управление состоянием, включая двигатель, открытие или закрытие дверей и т.д.);
  • игрок (кик, бан, изменение ника, скина, здоровья, оружия, брони и т.д., отображение сообщений, диалогов);
  • и так далее.

Нативные функции (правда, в неполном объеме) представлены здесь.

 

Фактически ваш игровой мод - это набор реализованных функций обратного вызова, в которых идет обработка происходящих на сервере событий, а также сопутствующие исходные тексты, чтобы выстроить из таких обработок систему. Скажем, в своем предыдущем сообщении я задействовал автовызываемые функции OnGameModeInit, OnPlayerDisconnect, OnDialogResponse. Для того, чтобы между этими автовызываемыми функциями передавать какие-то состояния (например, работает ли определенный игрок почтальоном, какой идентификатор соответствует пикапу для работы почтальоном), мы реализовали несколько переменных и массивов - именно посредством них и передаем состояния между callback-функциями (в одних устанавливаем эти состояния, в других читаем и выполняем опциональные действия).

 

В контексте одного файла игрового мода реализовывать несколько callback-функций в вашем случае нет никакой необходимости - такая практика обычно применяется для модульных проектов (пример есть здесь). Это означает, что исходный текст, помещенный в моем сообщении в тело автовызываемых функций, следует переместить в тело аналогичных функций вашего игрового мода. Переменные, массивы, процедуры, функции должны быть объявлены до того, как они будут использованы. Скажем, если вы сначала будете использовать переменную, а только ниже объявите компилятору, что существует такая переменная, компилятор выдаст ошибку, что логично: как он может обрабатывать неведомую ему сущность? Компилятор - примитивная программа, которая просматривает весь ваш исходный текст сверху сниз. Если компилятор встречает объявление лексемы, он фиксирует, что теперь в его лексиконе есть такая лексема, и в дальнейшем может ее обрабатывать. Если же он встречает использование неопределенной лексемы, то формирует ошибку, поскольку не знает, что это вообще такое и как с этим работать (его реакцию отражает данное видео).

Далее следует пример ошибки использования переменной до ее определения (решение - перенести объявление, чтобы оно было выше использования).

public OnPlayerConnect(playerid) {
    // выставляем флажок, что есть хотя бы один подключенный к серверу игрок
    gIsAnyPlayerConnected = true// <-- использование переменной
}

/*
    объявление переменной, в которой будет содержаться признак наличия
    хотя бы одного подключенного к серверу игрока
*/
new gIsAnyPlayerConnected; // <-- объявление переменной

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

public OnPlayerConnect(playerid) {
    // вызываем функцию с какой-то логикой
    someFunction(); // <-- использование функции
}

someFunction() { // <-- определение и объявление функции
    // тут какая-то логика
}

 

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

 

 

Поделиться сообщением


Ссылка на сообщение

Для публикации сообщений создайте учётную запись или авторизуйтесь

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

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!


Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.


Войти
  • Последние посетители   0 пользователей онлайн

    Ни одного зарегистрированного пользователя не просматривает данную страницу

  • Похожий контент

    • Dekmveka
      От Dekmveka
      Здравствуйте, уважаемые пользователи форума PAWNO-RUS.
       
      В этой теме хочу поделиться видеоуроками, ориентированных на новичков, которые сейчас начинают только изучать pawn. 
      Хочу сказать сразу, я не профессиональный блогер с крутым оборудованием, поэтому если что за какие то погрешности в съемке заранее извиняюсь.
      Хотелось бы попросить не писать, что типа pawn и samp уже умер, неактуален, уроков и так полно и так далее и тому подобное. Я лишь просто занимаюсь своим увлечением и решил делиться знаниями с новичками.
      Далее на канале после плейлиста с основами планируется выложить плейлист по MySQL и максимально подробно всё рассказать о MySQL, будет старая добрая рубрика "Мод с нуля" (но на основе плагинов, стандартов и др. актуальных в 2025-2026 году). 
       
      Также хочу сказать, что есть также телеграмм канал. 
      На данный момент там есть ветка для общения, ветка "Инструменты" (там лежат архивы со всем нужным + есть навигационный пост, я просто поделил всё на категории и просто вставил ссылки на архивы которые туда же выложил. Можете зайти посмотреть если интересно). Также в телеграмм канале потом будут исходные файлы с плейлиста "Мод с нуля" и других плейлистах, пока что говорить подробно не буду что буду ещё выкладывать. 
       
      В общем, я даю ссылки, кому интересно, можете смотреть.
      [Часть 1]: Архитектура ядра SAMP || Основы программирования PAWN/PAWNO  -  *кликабельно*
      [Часть 2]: База мода, переменные, format() || Основы программирования PAWN/PAWNO  -  *кликабельно*
      Telegram канал  -  *кликабельно*
       
      Желаю всем приятного просмотра, а также успехов в обучении 
    • DEST
      От DEST
      ДИНАМИЧЕСКИЕ ЗОНЫ (streamer плагин)
       
      ОБЩЕЕ ОПИСАНИЕ: 
      Как я заметил, многие интересуются, как создать действие для игрока в какой-либо определенной точке карты. Например, как выдать игроку бутылку пива автоматически при заходе в клуб? Конечно, можно это сделать, создав секундный таймер и выполнять действия там, но как по мне, динамические зоны справятся  с этим лучше. 
      ТРЕБОВАНИЯ: 
      Для работы необходимо: 
      1) Плагин streamer. 
      2) Инклуд streamer. 
      Желательно иметь актуальную версию плагина и инклуда, хотя это не обязательно. 
      ТЕХНИЧЕСКОЕ ОПИСАНИЕ РАБОТЫ: 
      Принцип работы данных зон прост: когда игрок заходит в зону, которая создается кстати, в виде геометрических фигур (об этом позже) для него срабатывает коллбэк - OnPlayerEnterDynamicArea. После того, как игрок покидает динамическую зону для него срабатывает другой коллбэк - OnPlayerLeaveDynamicArea. В оба эти коллбэка поступают одинаковые аргументы - playerid, areaid. Где playerid - ид игрока, который вошел / покинул зону, а areaid - ид самой зоны. 
      ТИПЫ СОЗДАВАЕМЫХ ЗОН: 
      1) Круг. Для создания данной зоны потребуются X и Y координата центра круга, а также радиус создаваемой зоны. 
      2) Прямоугольник. Для создания данной зоны, необходимо иметь координаты противоположных углов, образующих прямоугольник. 
      3) Сфера. Для данной зоны требуются X, Y, Z координаты центра сферы и ее размер (радиус). 
      4) Куб. Точно также как и прямоугольник, только потребуются еще и Z координаты противоположных углов. Рисунок не требуется. 
      Пример использования:
      new zone_army; public OnGameModeInit(playerid) { zone_army = zone51 = CreateDynamicCube(-13.0555,1702.1824, 15.0,405.9110, 2071.6646, 850.0); return 1; } public OnPlayerEnterDynamicArea(playerid, areaid) { if(areaid == zone_army) SendClientMessage(playerid,-1,"Покиньте охряняемую зону. Иначе будет открыт огонь."); return 1; } public OnPlayerLeaveDynamicArea(playerid, areaid) { if(areaid == zone_army) SendClientMessage(playerid,-1,"Благодарим за понимание."); return 1; } Пример взят с сайта forum-pawno.ru. 
      СВЯЗАННЫЕ ФУНКЦИИ: 
      DestroyDynamicArea(areaid); - уничтожение динамической зоны.  IsValidDynamicArea(areaid); - проверка за существование динамической зоны с данным ID.  TogglePlayerDynamicArea(playerid, areaid, toggle); - скрытие динамической зоны для игрока.  TogglePlayerAllDynamicAreas(playerid, toggle); - скрытие всех динамических зон для игрока.  IsPlayerInDynamicArea(playerid, areaid); - проверка на нахождение игрока в динамической зоне с определенным ID.  AttachDynamicAreaToPlayer(areaid, playerid); - прикрепление динамической зоны с определенным ID к игроку.  AttachDynamicAreaToVehicle(areaid, vehicleid); - прикрепление динамической зоны с определенным ID к машине.  DestroyAllDynamicAreas(); - уничтожение всех динамических зон.  CountDynamicAreas(); - подсчет количества динамических зон.  Внимание! К игрокам и машинам можно прикрепить только зоны с типом круг и сфера. 
      На этом все! 
      Благодарности: 
      Благодарность выражается следующим веб-ресурсам: 
      forum-pawno.ru
      forum.sa-mp.com
      Автор: @DEST.
       
    • MartinJoys
      От MartinJoys
      Всем привет на связи MartinJoys | Cherlock
      Cегодня мы научимся делать вип аккаунты по времени, с автоматическим удалением по истечению времени.
      Перейдем в самый вверх вашего мода и впишем туда этот код:
       
      Теперь необходимо установить подключение к базе при включении мода, перейдем в OnGameModeInit и впишем туда этот код:
       
      mysql_connect(MYSQL_HOST, MYSQL_USER, MYSQL_DB, MYSQL_PASS); //устанавливаем подключение switch(mysql_ping()) {     case 1: print("Соединение установлено"); // Если подключена БД.     case -1: print("Нет соединения с БД"); // Если не подключена БД. }    
      Теперь если все будет нормально то в консоли появится инфа о том что соединение установлено.
      Сейчас сделаем отключение от базы при выключении/перезагрузке мода, перейдем в OnGameModeExit и впишем:
      mysql_close(); Теперь нужно сделать проверку, переходим в OnPlayerConnect и вписываем:
       
       
      Теперь построим команду для выдачи випки. Внимание команда построена на YCM
       
      Теперь сделаем функцию выдачи випки, перейдем в низ вашего мода и напишем следующий код:  
      Теперь нужно создать таблицу в нашей бд:
      Создаем таблицу с именем Donate, делаем 2 столбца Name и Days.
      В первом укажем значение string(24), а во втором int(11).
       
      Необходимые для работы инклуды а так же плагины можете скачать по этой ссылкам:
      http://rghost.ru/40382201
      http://rghost.ru/40382221
      http://rghost.ru/40382234
      http://rghost.ru/40382569

      Автор: Я MartinJoys | Cherlock
       
    • Гость stibs
      От Гость stibs
      Всем привет! 
      Сегодня я вам поведаю  про такую прекрасную штуку как тернарный оператор. В принципе, тернарный оператор это такая же конструкция как и конструкция if/else. 
       
      Конструкция  оператора.
      условие ? правда : ложь
       
      Пример использования.
      Например, на конструкции if/else одно выражение может выглядеть вот так: 
      if (z > y) {     x = 5; } else {     x = 3; } А вот так это будет выглядеть с использованием тернарного оператора:
      x = (z > y) ? (5) : (3);  
    • kusehsup
      От kusehsup
      Здравствуйте.
      Решил рассказать про виды диалоговых окон.
       
      Начнем.
      Диалоги бывают 4-ех видов, это..
      DIALOG_STYLE_MSGBOX DIALOG_STYLE_INPUT DIALOG_STYLE_LIST DIALOG_STYLE_PASSWORD  
       
      Разберемся, что к чему.
       
       
      Первый вид диалога - DIALOG_STYLE_MSGBOX.
      Его действие - Показывает сообщение игроку. Пример: Правила сервера.
      Код диалога: 
      ShowPlayerDialog(playerid, 0, DIALOG_STYLE_MSGBOX, "Тут название", "Тут текст", "Кнопка1", "Кнопка2");  
      Второй вид диалога - DIALOG_STYLE_INPUT
      Его действие - Показывает сообщение игроку + есть поле для ввода информации. Пример: Ввод email при регистрации на РП сервере.
      Код диалога: 
      ShowPlayerDialog(playerid,1,DIALOG_STYLE_INPUT,"Тут название","Тут ваш текст","Кнопка1","Кнопка2");  
      Третий вид диалога - DIALOG_STYLE_LIST
      Его действие - Показывает игроку список. ( Диалог со списком ). Пример такого диалога - Команда /mn и тому подобное.
      Код диалога: 
      ShowPlayerDialog(playerid, 2, DIALOG_STYLE_LIST, "Тут название", "Пункт 1\nПункт 2", "Кнопка1", "Кнопка2");  
      Четвертый и последний вид диалога - DIALOG_STYLE_PASSWORD
      Его действие - Диалог с инфрмацией и полем для ввода, где введенные символы будут заменены на звездочки ( Поле для ввода пароля ).
      Код диалога: 
      ShowPlayerDialog(playerid, 3, DIALOG_STYLE_PASSWORD, "Тут название", "Тут текст(можете написать 'Введите пароль')", "Кнопка1", "Кнопка2");  
      На этом все