Ищу исполнителя для создания плагина(ов).

Сообщения
0
Реакции
0
Всем привет.

Необходим плагин на подобии WSS от Ёжика.

ТЗ:
1. Выдача через РКОН ( GameCMS )
2. Ручная выдача ( индивидуально для игрока )
3. Чтоб выдачи двумя способами не ругались друг с другом
4. Работающее меню смены ганов ( т.е если игрок купил через ркон несколько паков, чтоб они не заменяли друг друга и не было приоритета, а игрок мог сам спокойно поменять себе ган с того или иного пака, оружие должно меняться ( его визуал ), не с момента новой покупки с магазина пушек, а в новом раунде. )
Аналогично и с выданными в ручную, если выдали в ручную один пак, а второй он купил через ркон, то чтоб друг с другом не ругались, отображалось все верно и корректно в меню.

Можно обращаться в лс - по цене ( ваши предложения ).
 
Всем привет.

Необходим плагин на подобии WSS от Ёжика.

ТЗ:
1. Выдача через РКОН ( GameCMS )
2. Ручная выдача ( индивидуально для игрока )
3. Чтоб выдачи двумя способами не ругались друг с другом
4. Работающее меню смены ганов ( т.е если игрок купил через ркон несколько паков, чтоб они не заменяли друг друга и не было приоритета, а игрок мог сам спокойно поменять себе ган с того или иного пака, оружие должно меняться ( его визуал ), не с момента новой покупки с магазина пушек, а в новом раунде. )
Аналогично и с выданными в ручную, если выдали в ручную один пак, а второй он купил через ркон, то чтоб друг с другом не ругались, отображалось все верно и корректно в меню.

Можно обращаться в лс - по цене ( ваши предложения ).
Мне Сергей настраивал всё
 
Мне Сергей настраивал всё
У нас все настроено и работает по серверу уже как 15 лет)
Тут мне необходим именно плагин ( написать с нуля - выходит так ), который:
1. Не будет конфликтовать из пунктов, что я указал Выше.
2. Не будет конфликтовать с модом установленный на сервере.

А так спасибо за инфу, напишу ему, мб и поможет.
 
У нас все настроено и работает по серверу уже как 15 лет)
Тут мне необходим именно плагин ( написать с нуля - выходит так ), который:
1. Не будет конфликтовать из пунктов, что я указал Выше.
2. Не будет конфликтовать с модом установленный на сервере.

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

 
Зачем придумывать велосипед, если имеется плагин стабильно работающий?

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

Плагин от Ежика - работает как раз по моей задумке.

Суть в том, чтоб игрок мог приобрести сразу несколько паков и в самой игре комбинировать визуал оружия на свое.
Т.е он может:
1. Мку взять с одного пака ( если он купил пак )
2. Ак47 взять с другого пака ( если он купил пак )

Менять визуал по своему предпочтению при наличии купленных паков - в меню.

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

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

но естественно все выше сказанное не должно конфликтовать с ручной выдачей пака или паков.
 
scr
C-подобный:
#include <amxmodx>
#include <reapi>
#include <hamsandwich>

new const g_szPluginVersion[] = "0.1";
new const g_szConfigPath[] = "addons/amxmodx/configs/weapons_skins.ini";

#define MAX_WS_NAME_LEN 128
#define WEAPON_NULL -1

enum enumWeaponData {
    WeaponIdType:WEAPON_DATA_ID,
    WEAPON_UNIQUE_IMPULSE,
    WEAPON_DATA_KEY[MAX_AUTHID_LENGTH], 
    WEAPON_DATA_NAME[MAX_WS_NAME_LEN], 
    WEAPON_DATA_MODEL_VIEW[MAX_RESOURCE_PATH_LENGTH], 
    WEAPON_DATA_MODEL_WEAPON[MAX_RESOURCE_PATH_LENGTH], 
    WEAPON_DATA_MODEL_WORLD[MAX_RESOURCE_PATH_LENGTH]
};

new Array:g_aWeaponData;
new g_iCurrentWeaponIndex[MAX_PLAYERS+1][any:WEAPON_P90+1], WeaponIdType:g_iMenuTargetWeapon[MAX_PLAYERS+1];
new g_iImpulseCounter;

public plugin_precache() {
    register_plugin("Weapons skins", g_szPluginVersion, "Kurtis");
    _read_config();
}

public plugin_init() {
    if(g_aWeaponData == Invalid_Array || ArraySize(g_aWeaponData) == 0) {
        if(g_aWeaponData != Invalid_Array) {
            ArrayDestroy(g_aWeaponData);
        }
        set_fail_state("Не загружено ни одного скина, плагин остановлен");
        return;
    }

    RegisterHookChain(RG_CBasePlayer_AddPlayerItem, "CBasePlayer_AddPlayerItem_Post", 1);
    RegisterHookChain(RG_CBasePlayerWeapon_DefaultDeploy, "CBasePlayerWeapon_DefaultDeploy_Pre");
    RegisterHookChain(RG_CWeaponBox_SetModel, "CWeaponBox_SetModel_Pre");

    register_clcmd("say /skins", "cmdSkinsMenu");
    register_clcmd("say_team /skins", "cmdSkinsMenu");
}

public plugin_end() {
    if(g_aWeaponData != Invalid_Array) {
        ArrayDestroy(g_aWeaponData);
    }
}

public client_putinserver(pPlayer) {
    for(new any:i = WEAPON_P228; i <= any:WEAPON_P90; i++) {
        g_iCurrentWeaponIndex[pPlayer][i] = WEAPON_NULL;
    }

    new szAuthID[MAX_AUTHID_LENGTH];
    get_user_authid(pPlayer, szAuthID, charsmax(szAuthID));

    new eWeaponData[enumWeaponData];
    for(new i, iSize = ArraySize(g_aWeaponData); i < iSize; i++) {
        ArrayGetArray(g_aWeaponData, i, eWeaponData);

        new iWeaponId = any:eWeaponData[WEAPON_DATA_ID];

        if(g_iCurrentWeaponIndex[pPlayer][iWeaponId] == WEAPON_NULL && equal(szAuthID, eWeaponData[WEAPON_DATA_KEY])) {
            g_iCurrentWeaponIndex[pPlayer][iWeaponId] = i;
        }
    }
}

public cmdSkinsMenu(pPlayer) {
    if(!is_user_connected(pPlayer)) {
        return PLUGIN_HANDLED;
    }

    new szAuthID[MAX_AUTHID_LENGTH];
    get_user_authid(pPlayer, szAuthID, charsmax(szAuthID));

    new iMenu = menu_create("\yВыбор оружия для скина:", "_handlerSkinsMenu");
    new eWeaponData[enumWeaponData], szItemName[32];

    for(new any:i = WEAPON_P228; i <= any:WEAPON_P90; i++) {
        if(i == any:WEAPON_SHIELDGUN) {
            continue;
        }

        new bool:bHasSkins = false;
        for(new j = 0, iSize = ArraySize(g_aWeaponData); j < iSize; j++) {
            ArrayGetArray(g_aWeaponData, j, eWeaponData);
            if(any:eWeaponData[WEAPON_DATA_ID] == i && equal(szAuthID, eWeaponData[WEAPON_DATA_KEY])) {
                bHasSkins = true;
                break;
            }
        }

        if(bHasSkins) {
            _format_weapon_name(WeaponIdType:i, szItemName, charsmax(szItemName));

            new iCurrentIndex = g_iCurrentWeaponIndex[pPlayer][i];
            if(iCurrentIndex != WEAPON_NULL) {
                ArrayGetArray(g_aWeaponData, iCurrentIndex, eWeaponData);
                menu_additem(iMenu, fmt("%s \d[%s]", szItemName, eWeaponData[WEAPON_DATA_NAME]), fmt("%i", i));
            }
            else {
                menu_additem(iMenu, fmt("%s \d[Стандартный]", szItemName), fmt("%i", i));
            }
        }
    }

    if(menu_items(iMenu) == 0) {
        menu_destroy(iMenu);
        client_print_color(pPlayer, print_team_default, "^3[Skins] ^1У вас нет доступных скинов.");
        return PLUGIN_HANDLED;
    }

    menu_setprop(iMenu, MPROP_BACKNAME, "Назад");
    menu_setprop(iMenu, MPROP_NEXTNAME, "Далее");
    menu_setprop(iMenu, MPROP_EXITNAME, "Выход");

    menu_display(pPlayer, iMenu, 0);
    return PLUGIN_HANDLED;
}

public _handlerSkinsMenu(pPlayer, iMenu, iItem) {
    if(iItem == MENU_EXIT) {
        menu_destroy(iMenu);
        return;
    }

    new szItemNum[8];
    menu_item_getinfo(iMenu, iItem, .info = szItemNum, .infolen = charsmax(szItemNum));
    menu_destroy(iMenu);

    new WeaponIdType:iWeaponId = WeaponIdType:str_to_num(szItemNum);
    g_iMenuTargetWeapon[pPlayer] = iWeaponId;

    _SubSkinsMenu(pPlayer);
}

public _SubSkinsMenu(pPlayer) {
    new szAuthID[MAX_AUTHID_LENGTH];
    get_user_authid(pPlayer, szAuthID, charsmax(szAuthID));

    new WeaponIdType:iWeaponId = g_iMenuTargetWeapon[pPlayer];
    new szWpName[32];
    _format_weapon_name(iWeaponId, szWpName, charsmax(szWpName));

    new iMenu = menu_create(fmt("\yВыбор скина для \r%s:", szWpName), "_handlerSubMenu");
    new eWeaponData[enumWeaponData];

    menu_additem(iMenu, fmt("Стандартная модель %s %s", szWpName, (g_iCurrentWeaponIndex[pPlayer][any:iWeaponId] == WEAPON_NULL) ? "\r*" : ""), fmt("%i", WEAPON_NULL));

    for(new j, iSize = ArraySize(g_aWeaponData); j < iSize; j++) {
        ArrayGetArray(g_aWeaponData, j, eWeaponData);
        if(eWeaponData[WEAPON_DATA_ID] == iWeaponId && equal(szAuthID, eWeaponData[WEAPON_DATA_KEY])) {
            if(g_iCurrentWeaponIndex[pPlayer][any:iWeaponId] == j) {
                menu_additem(iMenu, fmt("%s \r*", eWeaponData[WEAPON_DATA_NAME]), fmt("%i", j));
            }
            else {
                menu_additem(iMenu, fmt("%s", eWeaponData[WEAPON_DATA_NAME]), fmt("%i", j));
            }
        }
    }

    menu_setprop(iMenu, MPROP_BACKNAME, "Назад");
    menu_setprop(iMenu, MPROP_NEXTNAME, "Далее");
    menu_setprop(iMenu, MPROP_EXITNAME, "Выход");

    menu_display(pPlayer, iMenu, 0);
}

public _handlerSubMenu(pPlayer, iMenu, iItem) {
    if(iItem == MENU_EXIT) {
        menu_destroy(iMenu);
        return;
    }

    new szItemNum[8];
    menu_item_getinfo(iMenu, iItem, .info = szItemNum, .infolen = charsmax(szItemNum));
    menu_destroy(iMenu);

    new iSelectedIndex = str_to_num(szItemNum);
    new WeaponIdType:iWeaponId = g_iMenuTargetWeapon[pPlayer];

    g_iCurrentWeaponIndex[pPlayer][any:iWeaponId] = iSelectedIndex;

    new szWpName[32];
    _format_weapon_name(iWeaponId, szWpName, charsmax(szWpName));

    if(iSelectedIndex == WEAPON_NULL) {
        client_print_color(pPlayer, print_team_default, "^3[Skins] ^1Вы вернули стандартный вид для ^4%s^1.", szWpName);
    }
    else {
        new eWeaponData[enumWeaponData];
        ArrayGetArray(g_aWeaponData, iSelectedIndex, eWeaponData);
        client_print_color(pPlayer, print_team_default, "^3[Skins] ^1Вы выбрали скин ^4%s ^1для ^4%s^1.", eWeaponData[WEAPON_DATA_NAME], szWpName);
    }

    cmdSkinsMenu(pPlayer);
}

public _format_weapon_name(WeaponIdType:iWeaponId, szOutput[], iMaxLen) {
    new szRawName[32];
    rg_get_weapon_info(iWeaponId, WI_NAME, szRawName, charsmax(szRawName));

    replace(szRawName, charsmax(szRawName), "weapon_", "");
    ucfirst(szRawName);

    copy(szOutput, iMaxLen, szRawName);
}

public CBasePlayer_AddPlayerItem_Post(pPlayer, iItem) {
    if(!is_user_alive(pPlayer) || is_nullent(iItem)) {
        return;
    }

    if(get_entvar(iItem, var_impulse) > 0) {
        RequestFrame("_delay_model_ver", pPlayer);
        return;
    }

    new WeaponIdType:iWeaponId = get_member(iItem, m_iId);
    if(iWeaponId == WEAPON_SHIELDGUN) {
        return;
    }

    if(g_iCurrentWeaponIndex[pPlayer][any:iWeaponId] == WEAPON_NULL) {
        return;
    }

    new eWeaponData[enumWeaponData];
    ArrayGetArray(g_aWeaponData, g_iCurrentWeaponIndex[pPlayer][any:iWeaponId], eWeaponData);

    set_entvar(iItem, var_impulse, eWeaponData[WEAPON_UNIQUE_IMPULSE]);

    RequestFrame("_delay_model_ver", pPlayer);
}

public CBasePlayerWeapon_DefaultDeploy_Pre(iItem, const szViewModel[], const szWeaponModel[], iAnim, const szAnimExt[], skiplocal) {
    if(is_nullent(iItem)) {
        return;
    }

    new iUniqueImpulse = get_entvar(iItem, var_impulse);
    if(iUniqueImpulse == 0) {
        return;
    }

    new WeaponIdType:iWeaponId = get_member(iItem, m_iId);
    if(iWeaponId == WEAPON_SHIELDGUN) {
        return;
    }

    new pPlayer = get_member(iItem, m_pPlayer);
    if(!is_user_alive(pPlayer)) {
        return;
    }

    new iArrayItem = _find_skin_by_impulse(iUniqueImpulse);
    if(iArrayItem != -1) {
        new eWeaponData[enumWeaponData];
        ArrayGetArray(g_aWeaponData, iArrayItem, eWeaponData);

        SetHookChainArg(2, ATYPE_STRING, eWeaponData[WEAPON_DATA_MODEL_VIEW]);
        SetHookChainArg(3, ATYPE_STRING, eWeaponData[WEAPON_DATA_MODEL_WEAPON]);
    }
}

public CWeaponBox_SetModel_Pre(eEnt, const szModel[]) {
    if(is_nullent(eEnt)) {
        return;
    }

    new iSlotItem, iUniqueImpulse;
    for(new iSlot; iSlot < MAX_ITEM_TYPES; iSlot++) {
        iSlotItem = get_member(eEnt, m_WeaponBox_rgpPlayerItems, iSlot);

        if(is_nullent(iSlotItem)) {
            continue;
        }

        iUniqueImpulse = get_entvar(iSlotItem, var_impulse);
        if(iUniqueImpulse == 0) {
            continue;
        }

        new iArrayItem = _find_skin_by_impulse(iUniqueImpulse);
        if(iArrayItem != -1) {
            new eWeaponData[enumWeaponData];
            ArrayGetArray(g_aWeaponData, iArrayItem, eWeaponData);

            SetHookChainArg(2, ATYPE_STRING, eWeaponData[WEAPON_DATA_MODEL_WORLD]);
            set_entvar(eEnt, var_impulse, iUniqueImpulse);
            break;
        }
    }
}

public _find_skin_by_impulse(iImpulse) {
    new eWeaponData[enumWeaponData];
    for(new i = 0, iSize = ArraySize(g_aWeaponData); i < iSize; i++) {
        ArrayGetArray(g_aWeaponData, i, eWeaponData);
        if(eWeaponData[WEAPON_UNIQUE_IMPULSE] == iImpulse) {
            return i;
        }
    }
    return -1;
}

public _delay_model_ver(pPlayer) {
    if(!is_user_alive(pPlayer)) {
        return;
    }

    new iActiveItem = get_member(pPlayer, m_pActiveItem);
    if(is_nullent(iActiveItem)) {
        return;
    }

    ExecuteHamB(Ham_Item_Deploy, iActiveItem);
}

public _read_config() {
    if(!file_exists(g_szConfigPath)) {
        set_fail_state("Отсутствует конфиг `%s`: плагин остановлен", g_szConfigPath);
        return;
    }

    g_aWeaponData = ArrayCreate(enumWeaponData);
    g_iImpulseCounter = 10423; // magic

    new INIParser:iParserHandle = INI_CreateParser();
    INI_SetReaders(iParserHandle, "OnKeyValue");
    INI_ParseFile(iParserHandle, g_szConfigPath);
    INI_DestroyParser(iParserHandle);
}

public bool: OnKeyValue(INIParser:handle, const key[], const value[], bool:invalid_tokens, bool:equal_token, bool:quotes, curtok, any:data) {
    new szData[512];
    copy(szData, charsmax(szData), key);
    trim(szData);

    if(szData[0] == EOS || szData[0] == '/') {
        return true;
    }

    new eWeaponData[enumWeaponData], szWeaponClassName[32];

    parse(szData,
        eWeaponData[WEAPON_DATA_KEY], MAX_AUTHID_LENGTH-1,
        szWeaponClassName, charsmax(szWeaponClassName),
        eWeaponData[WEAPON_DATA_NAME], MAX_WS_NAME_LEN-1,
        eWeaponData[WEAPON_DATA_MODEL_VIEW], MAX_RESOURCE_PATH_LENGTH-1,
        eWeaponData[WEAPON_DATA_MODEL_WEAPON], MAX_RESOURCE_PATH_LENGTH-1,
        eWeaponData[WEAPON_DATA_MODEL_WORLD], MAX_RESOURCE_PATH_LENGTH-1
    );

    if(eWeaponData[WEAPON_DATA_KEY][0] == EOS) {
        log_amx("Ошибка чтения конфига: не указан ключ (%s)", szData);
        return true;
    }

    if(containi(szWeaponClassName, "weapon_") == -1) {
        log_amx("Ошибка чтения конфига: указан неправильный класс оружия (%s)", szData);
        return true;
    }

    eWeaponData[WEAPON_DATA_ID] = WeaponIdType:rg_get_weapon_info(szWeaponClassName, WI_ID);

    if(eWeaponData[WEAPON_DATA_ID] == WEAPON_NONE) {
        log_amx("Ошибка чтения конфига: указан неправильный класс оружия (%s)", szData);
        return true;
    }

    if(!file_exists(eWeaponData[WEAPON_DATA_MODEL_VIEW])) {
        log_amx("Ошибка чтения конфига: проверьте наличие модели (%s)", szData);
        return true;
    }

    if(!file_exists(eWeaponData[WEAPON_DATA_MODEL_WEAPON])) {
        log_amx("Ошибка чтения конфига: проверьте наличие модели (%s)", szData);
        return true;
    }

    if(!file_exists(eWeaponData[WEAPON_DATA_MODEL_WORLD])) {
        log_amx("Ошибка чтения конфига: проверьте наличие модели (%s)", szData);
        return true;
    }

    precache_model(eWeaponData[WEAPON_DATA_MODEL_VIEW]);
    precache_model(eWeaponData[WEAPON_DATA_MODEL_WEAPON]);
    precache_model(eWeaponData[WEAPON_DATA_MODEL_WORLD]);

    eWeaponData[WEAPON_UNIQUE_IMPULSE] = g_iImpulseCounter++;

    ArrayPushArray(g_aWeaponData, eWeaponData);

    return true;
}

ini
C-подобный:
// Список скинов
// "SteamID" "Класс оружия" "Название" "v_ модель" "p_модель" "w_ модель"

"STEAM_2:1:1234567890" "weapon_ak47" "AK-47 Asimov" "models/weapons_skins/v_ak47_asi.mdl" "models/weapons_skins/p_ak47_asi.mdl" "models/weapons_skins/w_ak47_asi.mdl"
"STEAM_2:1:1234567890" "weapon_ak47" "AK-47 Gold" "models/weapons_skins/v_ak47_gold.mdl" "models/weapons_skins/p_ak47_gold.mdl" "models/weapons_skins/w_ak47_gold.mdl"

"STEAM_2:1:1234567890" "weapon_m4a1" "M4A1 Asimov" "models/weapons_skins/v_m4a1_asi.mdl" "models/weapons_skins/p_m4a1_asi.mdl" "models/weapons_skins/w_m4a1_asi.mdl"
"STEAM_2:1:1234567890" "weapon_m4a1" "M4A1 Gold" "models/weapons_skins/v_m4a1_gold.mdl" "models/weapons_skins/p_m4a1_gold.mdl" "models/weapons_skins/w_m4a1_gold.mdl"

Писал в целях развития
Нужно доработать:
1. Расширить систему (помимо чтения SteamID добавить ркон и ещё что вам нужно)
2. Сделать сохранение mysql

Скин устанавливается только при первом взятии, при выбросе любой может подобрать
Есть меню с выбором /skins
В теории не должно конфликтовать с другими кастомными оружиями
 

Вложения

Кто просматривает тему

Назад
Верх