Sign in to follow this  
Followers 0
Santa_Claus

Админ-бот v2

2 posts in this topic

Здравствуйте, взял и доработал вот - ниже.
 
Преимущества:


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

- Нам потребуется Pawn.CMD, sscanf2


Скрины: https://imgur.com/a/mCd67KF
GitHub: https://github.com/execution-lab/adminbot-include

 

Автор: execution

Доработка: Santa Claus

 

Ко всем константам

#define MAX_PLAYER_LISTITEM                    25             // Количество принимаемых listitem

#define    MAX_ADMIN_BOT_REQUEST                 3            // Максимальное количество принимаемых команд для запроса
#define    MAX_ADMIN_BOT_REQUEST_LENGTH        8            // Максимальная длина команды для запроса
#define    MAX_ADMIN_BOT_SUPPORT_COUNT            8            // Максимальное количество запросов
#define MIN_ADMIN_BOT_SUPPORT_COUNT            0            // Минимальное количество запросов
#define    MAX_ADMIN_BOT_PUNISH_REASON            50          // Максимальная длина причины в запросе
#define MAX_ADMIN_BOT_PUNISN_NAME_LENGTH    24            // Максимальная длина названия вида наказания
#define ADMIN_BOT_INVALID_REQUEST_ID        MAX_ADMIN_BOT_SUPPORT_COUNT + 1        // Недействительный ID запроса
#define ADMIN_BOT_HEX_COLOR                    0xFF6347FF     // Цвета сообщения админ-бота


enum // Константы ID диалогов
{
    dAbotreqinfo,
    dAbotreqmenu,
    dAbotreqlist
}

enum // Константы ошибок при проверке запроса
{
    CA_REQUEST_NOT_FOUND,
    CA_REQUEST_FOUND,
    CA_NO_PLACE_IN_REQUEST,
    CA_MISSING_ARGUMENT,
    CA_INVALID_TARGET_ID
}

enum e_ADMIN_BOT_INFO 
{
    aBot_punish_type,
    aBot_punish_time,
    aBot_punish_reason[MAX_ADMIN_BOT_PUNISH_REASON + 1],
    aBot_targetid,
    aBot_adminid,
    aBot_unix_time
} 

 

 

Ко всем глобал. переменным

new
    AdminBotInfo[MAX_ADMIN_BOT_SUPPORT_COUNT][e_ADMIN_BOT_INFO], // Информация запросов
    PlayerListitem[MAX_PLAYERS][MAX_PLAYER_LISTITEM] // Хранение записанных значений
;

new
    const ADMIN_BOT_PUNISH_NAME[MAX_ADMIN_BOT_REQUEST][MAX_ADMIN_BOT_PUNISN_NAME_LENGTH + 1] = // Название всех видов наказаний
    {
        "Заглушить",
        "Посадить в админ. тюрьму",
        "Посадить в тюрьму"
    };

new
    const ADMIN_BOT_SUPPORT_COMMAND[MAX_ADMIN_BOT_REQUEST][MAX_ADMIN_BOT_REQUEST_LENGTH] = // Название команд всех видов наказаний
    {  
        "/mute", 
        "/prison", 
        "/jail"
    };

new
    const ADMIN_BOT_LEVEL_USING_CMD[MAX_ADMIN_BOT_REQUEST] =  // Уровень возможности опирировать со всеми видами наказаний
    {
        3,
        3,
        3
    };
    
new
    gADMIN_BOT_SUPPORT_TOTAL_COUNT = 0, // Переменная записывающая количество запросов
    pAdminChoseRequest[MAX_PLAYERS char] // Массив хранения ID выбранного запроса
; 

 

 

Ко всем stock

/*
Функция:
    ShowPlayerAdminBotRequestInfo
Аргументы:
    playerid - ID игрока, которому показываем
Вернёт:
    1 - Показан успешно
    0 - Не удалось показать
Заметки:
    Показываем информацию о запросе выбранного из списка.
*/

stock ShowPlayerAdminBotRequestInfo(playerid)
{
    if(pAdminChoseRequest{playerid} == ADMIN_BOT_INVALID_REQUEST_ID)
        return 0;

    new
        count = pAdminChoseRequest{playerid},
        string[MAX_CHATBUBBLE_LEGNTH + 1]
    ;
    
    
    format(string, sizeof string, "\n\
        {C0F08E}Запросил: {FFFFFF}%s\n\
        {ED8473}Наказать: {FFFFFF}%s\n\n\
        Тип: %s\n\
        Время: %d мин\n\
        Причина: %s\n\n\n\
        %s",
        PlayerName(AdminBotInfo[count][aBot_adminid]),
        PlayerName(AdminBotInfo[count][aBot_targetid]),
        ADMIN_BOT_PUNISH_NAME[AdminBotInfo[count][aBot_punish_type]],
        AdminBotInfo[count][aBot_punish_time],
        AdminBotInfo[count][aBot_punish_reason],
        ADMIN_BOT_LEVEL_USING_CMD[AdminBotInfo[count][aBot_punish_type]] > AdminLevel(playerid) 
        ? ("{AFAFAF}Вы не можете принять запрос") : ("{E2BE1D}Вы можете принять запрос")
    );

    return ShowPlayerDialog(
        playerid,
        dAbotreqinfo,
        DIALOG_STYLE_MSGBOX,
        !" ",
        string,
        !"Хорошо", !""
    );
}

/*
Функция:
    ShowPlayerAdminBotRequestMenu
Аргументы:
    playerid - ID игрока, которому показываем
Вернёт:
    1 - Показан успешно
    0 - Не удалось показать
Заметки:
    Показываем меню запроса из списка.
*/

stock ShowPlayerAdminBotRequestMenu(playerid)
{
    if(pAdminChoseRequest{playerid} == ADMIN_BOT_INVALID_REQUEST_ID)
        return 0;

    return ShowPlayerDialog(
        playerid,
        dAbotreqmenu,
        DIALOG_STYLE_LIST,
        PlayerName(AdminBotInfo[pAdminChoseRequest{playerid}][aBot_targetid]),
        !"{C0F08E}Наказать\n{FFFFFF}Информация\nОтклонить", 
        !"Далее", !"Выход"
    );
}

/*
Функция:
    ShowPlayerAdminBotRequestList
Аргументы:
    playerid - ID игрока, которому показываем
Вернёт:
    1 - Показан успешно
Заметки:
    Показываем весь список запросов.
*/

stock ShowPlayerAdminBotRequestList(playerid)
{
    new
        string[(4 + ((MAX_PLAYER_NAME + 1 - 2) * 2) + (- 2 + MAX_ADMIN_BOT_PUNISH_REASON) + (- 2 + MAX_ADMIN_BOT_PUNISN_NAME_LENGTH) 
        + (- 2 + 4)) * MAX_ADMIN_BOT_SUPPORT_COUNT + 46] = 
        {
            "Запросил\tДейсвтие(время)\tНаказать\tПричина\n"
        },

        count = 0
    ;

    for(new iter = 0; iter < MAX_ADMIN_BOT_SUPPORT_COUNT; iter ++)
    {
        if(IsEmptyRequestInAdminBotList(iter))
                continue;
            
        format(string, sizeof string, "%s%s\t%s(%d мин)\t%s\t%s\n",
            string,
            PlayerName(AdminBotInfo[iter][aBot_adminid]),
            ADMIN_BOT_PUNISH_NAME[AdminBotInfo[iter][aBot_punish_type]],
            AdminBotInfo[iter][aBot_punish_time],
            PlayerName(AdminBotInfo[iter][aBot_targetid]),
            AdminBotInfo[iter][aBot_punish_reason]
        );

        PlayerListitem[playerid][count++] = iter;

    }

    return ShowPlayerDialog(
        playerid,
        dAbotreqlist,
        DIALOG_STYLE_TABLIST_HEADERS,
        !"Запросы админ-боту",
        string,
        !"Далее", !""
    );
}

/*
Функция:
    GetLastRequestInAdminBot
Аргументы:
    -
Вернёт:
    Вернёт ID последнего запроса.
    Вернёт -1, если спиоск запросов пуст.
Заметки:
    Получить ID последнего добавленного запроса.
*/

stock GetLastRequestInAdminBot()
{
    new
        tmp_ = -1;
    
    if(CountRequestInAdminBotList() == MIN_ADMIN_BOT_SUPPORT_COUNT)
        return tmp_;

    for(new iter = 0; iter < MAX_ADMIN_BOT_SUPPORT_COUNT; iter ++)
    {
        if(IsEmptyRequestInAdminBotList(iter))
                continue;
        
        if((tmp_ == -1) || (tmp_ != -1 && AdminBotInfo[iter][aBot_unix_time] > AdminBotInfo[tmp_][aBot_unix_time]))
        {
            tmp_ = iter;
        }
    }
    
    return tmp_;
}

/*
Функция:
    CountRequestInAdminBotList
Аргументы:
    -
Вернёт:
    Число созданных запросов.
Заметки:
    -
*/

stock CountRequestInAdminBotList()
{
    return gADMIN_BOT_SUPPORT_TOTAL_COUNT;
}

/*
Функция:
    CheckAvailabilityInAdminBot
Аргументы:
    playerid - ID игрока, подающий запрос
    parmas[] - Массив с хранением запроса
Вернёт:
    CA_REQUEST_NOT_FOUND - Запрос не найден
    CA_REQUEST_FOUND - Запрос создан/найден
    CA_NO_PLACE_IN_REQUEST - Лист с запросами переполнен
    CA_MISSING_ARGUMENT - Указаны не все аргументы
    CA_INVALID_TARGET_ID - Наказуемый не в сети
Заметки:
    Проверяем наличие элементов запроса. 
*/

stock CheckAvailabilityInAdminBot(playerid, params[])
{
    new
        bool:IsFinedCommand = false,

        strFindPos,

        supportCommand[MAX_ADMIN_BOT_REQUEST_LENGTH + 1],
        supportTargetid,
        supportTime,
        supportReason[MAX_ADMIN_BOT_PUNISH_REASON + 1],
        supportUnixtTime = gettime(),

        string[MAX_CHATBUBBLE_LENGTH + 1]
    ;

    for(new i = 0; i < MAX_ADMIN_BOT_REQUEST; ++i)
    {
        if((strFindPos = strfind(params, ADMIN_BOT_SUPPORT_COMMAND[i], true)) != -1)
        {
            if(CountRequestInAdminBotList() >= MAX_ADMIN_BOT_SUPPORT_COUNT)
                return CA_NO_PLACE_IN_REQUEST;

            strdel(params, 0, strFindPos);

            if(sscanf(params, "s[8]uds[50]",
                supportCommand, supportTargetid, supportTime, supportReason))
                return CA_MISSING_ARGUMENT;
            
            if(supportTargetid == INVALID_PLAYER_ID)
                return CA_INVALID_TARGET_ID;
        

            for(new j = 0; j < MAX_ADMIN_BOT_SUPPORT_COUNT; j ++)
            {
                if(!IsEmptyRequestInAdminBotList(j))
                    continue;
                
                format(string, sizeof string, "[ADMIN-BOT] {FFFFFF}%s запросил %s игрока %s на %d мин, причина: %s",
                    PlayerName(playerid), 
                    ADMIN_BOT_PUNISH_NAME[i], 
                    PlayerName(supportTargetid),
                    supportTime,
                    supportReason
                );
                SendAdminMessage(ADMIN_BOT_HEX_COLOR, string);

                SendAdminMessage(ADMIN_BOT_HEX_COLOR, !"Нажмите Y для одобрения, N для отказа. (/viewreq для просмотра всех запросов)");

                SetRequestInAdminBotList(
                    j, 
                    i, 
                    supportTime, 
                    playerid, 
                    supportTargetid, 
                    supportUnixtTime, 
                    supportReason
                );

                IsFinedCommand = true;

                break;
            }
            break;
        }
    }

    return (IsFinedCommand ? CA_REQUEST_FOUND : CA_REQUEST_NOT_FOUND);
}

/*
Функция:
    RejectRequestInAdminBotList
Аргументы:
    playerid - ID игрока, отклоняющий запрос
    index - ID запроса
Вернёт:
    -
Заметки:
    Отклоняем запрос. 
*/

stock RejectRequestInAdminBotList(playerid, index)
{
    new
        string[MAX_CHATBUBBLE_LENGTH + 1];

    format(string, sizeof string, "[ADMIN-BOT] {FFFFFF}%s отклонил запрос №%d",
        PlayerName(playerid), index + 1);
    SendAdminMessage(ADMIN_BOT_HEX_COLOR, string);

    format(string, sizeof string, "(Отправитель: %s | Просьба: %s | Наказуемый: %s | Причина: %s)",
        PlayerName(AdminBotInfo[index][aBot_targetid]),
        ADMIN_BOT_PUNISH_NAME[AdminBotInfo[index][aBot_punish_type]],
        PlayerName(AdminBotInfo[index][aBot_adminid]),
        AdminBotInfo[index][aBot_punish_reason]
    );
    SendAdminMessage(ADMIN_BOT_HEX_COLOR, string);

    DeleteRequestInAdminBotList(index);
}

/*
Функция:
    ApproveRequestInAdminBotList
Аргументы:
    playerid - ID игрока, принимающий запрос
    index - ID запроса
Вернёт:
    -
Заметки:
    Принимаем запрос. 
*/

stock ApproveRequestInAdminBotList(playerid, index)
{
    new
        string[MAX_CHATBUBBLE_LENGTH + 1];

    format(string, MAX_CHATBUBBLE_LENGTH + 1, "%s %d %d %s // %s",
            ADMIN_BOT_SUPPORT_COMMAND[AdminBotInfo[index][aBot_punish_type]],
            AdminBotInfo[index][aBot_targetid],
            AdminBotInfo[index][aBot_punish_time],
            AdminBotInfo[index][aBot_punish_reason],
            PlayerName(AdminBotInfo[index][aBot_adminid])
    );
    PC_EmulateCommand(playerid, string);

    DeleteRequestInAdminBotList(index);
}

/*
Функция:
    IsEmptyRequestInAdminBotList
Аргументы:
    index - ID запроса
Вернёт:
    1 - Запрос пустой
    0 - Запрос не пустой
Заметки:
    Смотрим, пустой ли запрос. 
*/

stock IsEmptyRequestInAdminBotList(index)
{
    return ((AdminBotInfo[index][aBot_punish_reason][0] == '\0') ? (1) : (0));
}

/*
Функция:
    DeleteRequestInAdminBotList
Аргументы:
    index - ID запроса
Вернёт:
    1 - Запрос успешно удалён
    0 - Запрос не был удалён
Заметки:
    Удаляем запрос из списка. 
*/

stock DeleteRequestInAdminBotList(index)
{
    if(!IsEmptyRequestInAdminBotList(index))
    {
        AdminBotInfo[index][aBot_targetid] = INVALID_PLAYER_ID;
        AdminBotInfo[index][aBot_punish_reason][0] = '\0';

        gADMIN_BOT_SUPPORT_TOTAL_COUNT --;

        return 1;
    }
    else
    {
        return 0;
    }
}

/*
Функция:
    SetRequestInAdminBotList
Аргументы:
    index - ID запроса
    type - Тип запроса (заглушка и т.п.)
    &time - Время в минутах
    &adminid - ID админа, оставившего запрос
    &targetid - ID наказуемого
    &unix_time - Unix время на момент добавления запроса
    reason[] - Причина наказания
    size - Размер массива с причиной (по-умолчании установлен) 
Вернёт:
    -
Заметки:
    Добавляем запрос в список 
*/

stock SetRequestInAdminBotList(index, type, &time, &adminid, &targetid, &unix_time, reason[], const size = sizeof reason)
{
    AdminBotInfo[index][aBot_punish_type] = type;
    AdminBotInfo[index][aBot_punish_time] = time;

    strmid(
        AdminBotInfo[index][aBot_punish_reason],
        reason,
        0,
        MAX_ADMIN_BOT_PUNISH_REASON,
        size
    );
    
    AdminBotInfo[index][aBot_targetid] = targetid;
    AdminBotInfo[index][aBot_adminid] = adminid;
    AdminBotInfo[index][aBot_unix_time] = unix_time;

    gADMIN_BOT_SUPPORT_TOTAL_COUNT ++;
} 

 

 

 

Ко всем командам

CMD:viewreq(playerid) // Для просмотра всех запросов
{
    if(!AdminLevel(playerid)) 
        return 1; CheckAdminLevel(playerid, CMD_ADMIN_viewreq);

    if(CountRequestInAdminBotList() == MIN_ADMIN_BOT_SUPPORT_COUNT)
        return SendClientMessage(playerid, -1, !"Список запросов пуст.");

     ShowPlayerAdminBotRequestList(playerid) 

    return 1;
}

CMD:admin(playerid, params[]) // Админ-чат
{
    if(AdminLevel(playerid))
    {
        if(!(0 < strlen(params) < 90))
            return SendClientMessage(playerid, -1, !"Используйте больше 1 символа и меньше 90");

        new
            string[128];

        format(string, sizeof(string), "[A] %s [%d]: %s", PlayerName(playerid), playerid, params);
        SendAdminMessage(-1, string);

        new
            ret = CheckAvailabilityInAdminBot(playerid, params),
            retrunMessage[][] =
            {
                !"Не удалось найти элементов запросов",
                !"Запрос успешно найден и зарегистрирован",
                !"К сожалению лист с запросами переполнен.",
                !"Указаны не все аргументы. (Например: /mute (Id/Nick) (Time) (Reason)",
                !"Данного игрока нет на сервере."
            }
        ;

        SendClientMessage(playerid, -1, retrunMessage[ret]);
    }

    return 1;
}
alias:admin("a"); 

 

 

 

OnDialogResponse

case dAbotreqinfo:
{
    return ShowPlayerAdminBotRequestMenu(playerid);
}

case dAbotreqmenu:
{
    if(!response)
    {
        pAdminChoseRequest{playerid} = ADMIN_BOT_INVALID_REQUEST_ID;

        return 1;
    }

    if(IsEmptyRequestInAdminBotList(pAdminChoseRequest{playerid}))
        return SendClientMessage(playerid, -1, !"Данный запрос был удалён");
    
    new
        count = pAdminChoseRequest{playerid};

    switch(listitem)
    {
        case 0:
        {
            if(ADMIN_BOT_LEVEL_USING_CMD[AdminBotInfo[count][aBot_punish_type]] > AdminLevel(playerid))
            {
                pAdminChoseRequest{playerid} = ADMIN_BOT_INVALID_REQUEST_ID;

                return SendClientMessage(playerid, -1, !"Вы неуполномочены принимать данный запрос.");
            }
            
            pAdminChoseRequest{playerid} = ADMIN_BOT_INVALID_REQUEST_ID;

            ApproveRequestInAdminBotList(playerid, count);

            return 1;
        }
        case 1:
        {
            return ShowPlayerAdminBotRequestInfo(playerid);
        }
        case 2:
        {

            if((AdminBotInfo[count][aBot_adminid] != playerid) 
            && (ADMIN_BOT_LEVEL_USING_CMD[AdminBotInfo[count][aBot_punish_type]] > AdminLevel(playerid)))
            {
                pAdminChoseRequest{playerid} = ADMIN_BOT_INVALID_REQUEST_ID;

                return SendClientMessage(playerid, -1, !"Вы неуполномочены отлонять данный запрос");
            }
            
            pAdminChoseRequest{playerid} = ADMIN_BOT_INVALID_REQUEST_ID;

            RejectRequestInAdminBotList(playerid, count);

            return 1;
        }
    }
    return 1;
}

case dAbotreqlist:
{
    if(!response)
        return 1;
    
    new
        count = PlayerListitem[playerid][listitem];

    if(IsEmptyRequestInAdminBotList(count))
    {
        SendClientMessage(playerid, -1, !"Данный запрос был удалён");
        return ShowPlayerAdminBotRequestList(playerid);
    }

    pAdminChoseRequest{playerid} = count;
    
    return ShowPlayerAdminBotRequestMenu(playerid);
} 

 

 

 

OnPlayerConnect

pAdminChoseRequest{playerid} = ADMIN_BOT_INVALID_REQUEST_ID; 

 

 

OnPlayerDisconnect

    if(CountRequestInAdminBotList() != MIN_ADMIN_BOT_SUPPORT_COUNT) // Если список запрос не пуст
    {
        for(new iter = 0; iter < MAX_ADMIN_BOT_SUPPORT_COUNT; iter ++) // Перебираем все запросы
        {
            if(AdminBotInfo[iter][aBot_adminid] != playerid && AdminBotInfo[iter][aBot_targetid] != playerid) // Если ID игрока не равен админу, который запросил и наказуемого - пропускаем
                continue;
            
            DeleteRequestInAdminBotList(iter); // Удаляем запрос
        }
    } 

 

 

 

OnPlayerKeyState

if(newkeys & KEY_NO)
{
    if(CountRequestInAdminBotList() != MIN_ADMIN_BOT_SUPPORT_COUNT)
    {
        if(AdminLevel(playerid))
        {
            new
                iter = GetLastRequestInAdminBot();

            if(iter != -1)
            {
                if(ADMIN_BOT_LEVEL_USING_CMD[AdminBotInfo[iter][aBot_punish_type]] > AdminLevel(playerid))
                {
                    SendClientMessage(playerid, -1, !"Малый уровень администрирования для отказа.");

                    return 1;
                }
                
                RejectRequestInAdminBotList(playerid, iter);

                return 1;
            }
        }
    }
}

if(newkeys & KEY_YES)
{
    if(CountRequestInAdminBotList() != MIN_ADMIN_BOT_SUPPORT_COUNT)
    {
        if(AdminLevel(playerid))
        {
            new
                iter = GetLastRequestInAdminBot();

            if(iter != -1)
            {    
                if(ADMIN_BOT_LEVEL_USING_CMD[AdminBotInfo[iter][aBot_punish_type]] > AdminLevel(playerid))
                {
                    SendClientMessage(playerid, -1, !"Малый уровень администрирования для принятия.");

                    return 1;
                }
                
                ApproveRequestInAdminBotList(playerid, iter);
            }
        }
    }
} 

 

 

 

Заменяемые под себя функции / макросы

Спойлер

В начало мода или ко всем итераторам


new 
    Iterator:Connect_Admin<MAX_PLAYERS>; // Итератор , где будем хранить всех администраторов 

 

При добавлении/заходе администратора


if(!Iter_Contains(Connect_Admin, /*админ*/)) Iter_Add(Connect_Admin, /*админ*/); 

 

 
При выходе/снятии администратора

if(Iter_Contains(Connect_Admin, /*админ*/)) Iter_Remove(Connect_Admin, /*админ*/); 

 

 

 

Сток для отправки сообщения администраторам


stock SendAdminMessage(color, const string[])
{
    foreach(new i : Connect_Admin)
    {
        SendClientMessage(i, color, string);
    }
    return 1;
} 

 

 

Спойлер

Макросы



#define PlayerName(%0)                 /*Массив с хранением имени игрока*/
#define AdminLevel(%0)                /*Массив с хранением админ-уровня*/ 

 

 

 

 

 

Изменение:

*Добавлена возможность подключить как include.

*Мы оптимизировали админ-бота.

*Убраны лишние строки.

 

Share this post


Link to post
Share on other sites

АВТОМАТИЧЕСКИ СФОРМИРОВАННОЕ СООБЩЕНИЕ:

Данная тема была перемещена модерацией или администрацией портала PAWNO-RUS.RU! 

Перемещена из: "Скриптинг PAWN > Готовые решения"

Перемещена в: "Прочее > Архив"

 

С уважением, ваш Бот! 

Если вы НЕ согласны с переносом данной темы в раздел "Прочее > Архив", пожалуйтесь на это сообщение в жалобе указав причины вашего недовольства. Спасибо. 

 

Share this post


Link to post
Share on other sites
Guest
This topic is now closed to further replies.
Sign in to follow this  
Followers 0

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • Tony_Cannabis
      By Tony_Cannabis
      Нужна мне собственно проверка на гараж, я хочу чтобы дом N класса не имел гаража, куда только я проверку эту не сувал, но немогу понять как это работает
       
      Имеем код
      Куда мне ее засунуть просто ума не приложу, думал будет легко но понимаю что без вас не разобратся, проверку которую хотел закинуть см. ниже
      if(gHouses[houseid][houseClass] == 0) return ErrorMessage(playerid, "Недоступно для класса Вашего дома");  
    • danya_white
      By danya_white
      Доброго времени суток, хочу выставить на продажу игровой мод проекта Dallas RP.
      Данный мод полностью доработан и был на открытие проекта, подходит как для бонусного проекта, так и для без бонусного проекта.
      Очень много интересных актуальных систем, ниже на скриншотах можете увидеть.
       
      Информация о моде:
      Версия MYSQL - R41-4
      Стример - Streamer Plugin v2.9.4 by Incognito
      Командный процессор - Pawn CMD
      Основа мода - Motion RP
      Остальное Все плагины обновлены до последней версии
       
       
      Основные системы которые присутствуют в данном моде:
      - Исправлены все недочёты, которые успел заметить - Переписал создание домов (криво создавались) - Исправил недоработку с прорисовкой объектов - Переписал donate - Добавил Perfomance для личного т.с - Добавил финансовую статистику для бизнесов/АЗС - В систему семей добавил банк - Добавил в семью заместителя (возможность назначать/снимать) - Добавил систему багажника для личного т.с /baggage (реализация так себе конечно) - В донат добавил возможность покупки попугая (можно придумать ему имя, улучшить, чем больше уровень улучшений - тем чаще повторяет /toy) - В донате можно купить любой номерной знак - Добавил команду /park - возможность самостоятельно припарковать авто в радиусе 100м от дома - Переделал оформление немного - Новые команды для админов (/msgr - сообщение в радиусе для игроков, /gfinka /bfinka - просмотр финки бизнеса/АЗС, /crashed - крашнуть игрока) - Если у админа различаются последний и текущий IP-адрес его права должен подтвердить старший администратор (/acceptadmin) - Добавил возможность изменять освещение в доме - Добавил новые интерьеры для домов (маппинг с паблика) - В мэрии можно посмотреть статистику игроков (самые богатые, старые, донатеры и т.д.) - Теперь создать семью можно в семейном центре (5 уровень и 5.000.000$) - Теперь, чтобы вступить в организацию или стать лидером - нужно пройти простой RP-тест (/menu) - Убрал поочерёдную систему репорта (теперь стандартная) - Добавил новые функции для VIP (в планах полностью её переписать) - В /menu теперь доступен ежедневный подарок (может выпасть что угодно, доступно с 3 уровня) - В /apanel теперь можно посмотреть список игроков онлайн с мутом, в тюрьме - В /apanel для старшей администрации теперь доступна функция отключать/включать доступ к казино - Поменял интерьер в казино (переделать /dice и сделать крупье) - Добавил команду /boostinfo (посмотреть текущие акции для игроков) - Теперь при наличии более 10.000.000$ на руках у игрока появляется мешок с деньгами (можно убрать в настройках) - В настройках можно изменить стиль игрового чата (как на Advance RP) - Добавил /lmenu (возможность зареспавнить незанятый транспорт организации, посмотреть список игроков во фракции, управление банком организации) - В /lmenu для президента добавлена возможность просмотра казны и управления налогом - Для лидеров банд добавлена команда /fpay - выдать премию членам организации в сети - Добавил команду /vacancy (можно посмотреть доступные вакансии, а лидерам организаций добавить их) - Сделал систему репутации для администраторов (после ответа на репорт игрок может оценить ответ) - Добавлена справочная книжка (/dir - посмотреть заместителей и т.д.) - Полностью переписана система обработки объявлений для СМИ - Система погоды (каждые 20 минут меняется погода в штате) - В /apanel основателю можно изменять название сервера - При создании дома можно указать наличие гаража (0 - нет, 1 - да), добавлена система гаражей, он есть не у всех домов. Если в доме имеется гараж, то нельзя использовать /park - Исправил недочёты с попугаем (сохранение) - Добавил в /apanel телепорт в админ.зону (также доступна /az [id игрока] для телепорта в зону) - Добавил новый интерьер для армий - В /donate добавлена возможность обнулить трудовую книжку - Теперь, чтобы убрать временный скин, можно ввести команду /end - МВД и мафиям сделана команда /object (заграждения, объекты), также при установке пишет ID игрока, который его установил (/break убрана) - Добавлена система аксессуаров (можно приобрести пока что только в донате или выдать от имени администратора или получить в семейном центре) - Добавлена команда /vad. С помощью неё Вы сможете выделить своё объявление как VIP (стоимость услуги 2500$) - Для бандитов добавил возможность грабить транспорт в гетто (/robcar, copy Advance). Владельцы ограбленного авто должны будут оплатить его ремонт в полицейском участке. - Помимо VIP сделан статус PREMIUM, у которого есть свои привилегии - Добавлены печенья (их можно обменять на что-то ценное) - Сотрудникам СМИ добавлена команда /skin > продать костюм игроку - Добавлен новый класс дома - Luxury, у этого класса желтый пикап (отличие от остальных) - Теперь вместо чекпоинтов у домов - пикапы - В семья добавлены ранги. Всего 5 рангов, названия может менять только владелец семьи. Теперь игрок с 4 рангом в семье может принимать и выгонять из семьи - Добавлен семейный центр в ЛС (у автошколы). Там можно создать семью, посмотреть рейтинг семей, обменять печенье на призы - Переписаны банки. Теперь есть Центральный банк в ЛС и его филиалы в СФ и ЛВ, в ЦБ можно создавать счета и т.д., а в филиалах доступны депозитные счета. Процентная ставка зависит от статуса (обычный - 0.1%, ВИП - 0.5%, ПРЕМИУМ - 1.5%), пополнять и снимать средства с депозитного счёта можно раз в сутки - В банки добавлены говорящие актеры (анимка и текст над головой) - Переписана команда /tp - Сделал систему репутации для администраторов (после ответа на репорт, игрок может оценить ответ) - Сделал тип бизнеса - бар (свой интерьер добавил) - Сделан функционал обмена печенья на ценные призы в "Семейном центре". Вы можете обменять 20 шт. печенья на рандомный приз. Печенье выдаётся каждый час по 1 шт. (вип игрокам - 3 шт., премиум игрокам - 5 шт.) P.S В скором времени планирую добавить квесты, за выполнение тоже будут выдаваться печенья - Администраторам добавлена команда /getowner (посмотреть владельца т/с) - Управление семьей перенесено в /mn > управление аккаунтом > управление семьей - Владелец семьи теперь может привязать дом к семье, игроки смогут в нем спавниться, правда для этого класс дома должен быть как минимум "Элитный". - Покинуть и удалить семью теперь можно только в семейном центре - В 3D тексте у дома пишет название семьи, которой принадлежит дом - Теперь в семейном центре можно изменить название семьи - Когда разгружаешь ящики с патронами или медикаментами на склад организации (об этом пишет в чат фракции) - Исправлен баг с отображением времени при bizwar у мафий - Теперь античит не срабатывает на SpeedHack, если Вы используете Perfomance Tuning - При смене ника в таблице MySQL теперь изменяется ник зама и лидера (если игрок таковым является) - В /time пишет время заключения и затычки (если они есть) - В больницы добавлены регистратуры, там можно пройти курс платного лечения (мгновенно вылечиться), если на сервере отсутсвуют мед.работники учереждения, в котором находится игрок (если работники есть - вылечиться будет нельзя) - Исправлен баг с пикапом на сдачу экзамена в АШ - В автошколу добавлен вертолёт, а также возможность сдать экзамен на воздушный транспорт (сделана практическая сдача) - В /lmenu добавлена возможность создавать объявления для сотрудников (они смогут его посмотреть с помощью команды /advert) - Добавлен PREMIUM авторынок в СФ для обладателей PREMIUM аккаунта. Там можно приобрести транспорт, который не купишь в обычном автосалоне. На авторынке доступно ограниченное количество автомобилей (админы могут добавить командой /addcar [модель машины] [цена]) - Добавлены ключи от камеры в КПЗ, при наличии ключа Вы сможете выйти из тюрьмы с помощью команды /unjail. Ключи можно получить через донат или обменяв на печенье в семейном центре. - В семейном центре при обмене печенья теперь можно получить PREMIUM (шанс очень маленький, но всё же) - Исправил команду /respv (выдавало в лог ошибку) - Исправлен баг со сдачей прав - Исправлен баг с выдачей аксессуаров командой /giveaccs (путались слоты) - При регистрации можно указать национальность персонажа (в дальнейшем будет функционал для этого) - В порту СФ добавлен продавец семян Ричи. Он появляется в 10:00, 14:00, 18:00 и 00:00 по серверному времени. У него бандиты могут приобрести семена, с помощью которых можно выращивать куст конопли (/plant), после выращивания куста получаются наркотики. Их бандиты могут продать в притон (в гетто). - Переписан притон в гетто. Теперь лидеру банды, которая контролирует территорию с притоном доступна команда /hangout. Там можно изменить цену на продажу и покупку наркотиков, а также пополнить баланс или снять с баланса притона денежные средства - Исправлен баг с аксессуарами (путались слоты) - Убрана команда /selldrugs (за ненадобностью) - Исправлен баг с /alogin, когда аккаунт только что зарегистрирован - Теперь проверка на совпадение IP действует на всех администраторов кроме 6 уровня - В /report теперь нельзя подать жалобу на самого себя - Добавлена система достижений. На данный момент сделано 5 достижений, за выполнение которых игроку выдаётся уникальный аксессуар, который нигде нельзя приобрести. Информацию о достижениях можно посмтреть в меню /mn > 10 пункт - Переписана система промокодов. Отныне существует 3 типа промокодов - для гос, банд и ловцов имущества. Администраторы могут создавать и удалять промокоды командами /addpromo, /dellpromo. Также можно смотреть статистику промокодов /promolist. Промокод устанавливается на определенного игрока (держатель промо), он может просматривать подробную статистику промокода (кол-во активаций, дата создания) Игрок, который активировал промокод, может просматривать информацию о бонусах, которые ему достанутся по достижении определенного уровня. - Игрокам от 3 уровня добавлена команда /pame - установить описание персонажа (сохраняется при перезаходе) - Администраторам добавлена команда /apame - удалить описание персонажа у игрока - Теперь при бане/варне слетает админка - Переписано обнуление игроков при подключении/отключении с сервера - Теперь в 24/7 можно купить шашку Taxi и работать таксистом на личном авто, при этом трудоустраиваться не нужно (/taxi) - В /lmenu лидер теперь может изменять цвет организации в формате hex-color - Команда /logs теперь работает исправно (просмотр последних 25 действий администратора к игроку) - Теперь в личном меню игрок может посмотреть 25 последних наказаний на своём аккаунте - Теперь каждый PayDay обновляется рейтинг семей (рейтинг даётся семье если игрок лидер, имеет VIP или PREMIUM) - Администраторам 6 уровня добавлена команда /bizlock (заблокировать доступ к бизнесу) - В /apanel для 5 уровней добавлен топ донатеров - Добавлена команда /jp (получить jetpack) для администраторов 3 уровня - В /apanel возвращены настройки администратора (информация о подключении игроков, просмотр килллиста) - Добавлена реклама на сервер с полезной информацией - Добавлена система подсказок (/hint). Теперь с получением нового уровня, игроку будет доступна подсказка об игре на сервере (пока сделал для 3 уровней) - Добавлен TextDraw телефона (показывается дата, можно позвонить, посмотреть контакты, отправить смс) - Убраны команды /contacts, /call - вместо них добавлена /phone (меню телефона) - Исправлена смена имени за донат и /okay - Теперь корректно списывается донат (сохранение) - Исправлен баг, когда по окончанию войны за территорию у бандитов не пропадали 3D текста над головой - Переписаны гангзоны (теперь ровные квадратики, всего 108 территорий) - Добавлена админ комната (телепортироваться можно через /apanel) - Добавлена команда /az, для того чтобы телепортировать игрока на собеседование в админ.комнату - В админ комнату добавлена общая статистика сервера p.s И еще многие другие системы, более подробно на тестовом сервере.