[ReAPI] Пример кастомного оружия с дополнительними свойствами

Сообщения
52
Реакции
78
w0w, fantom, в таком случае, я обеими руками с Вами За!) Будем ждать реализации идеи и решать остальные вопросы по мере их поступления.
 
Сообщения
2,143
Реакции
1,225
Помог
44 раз(а)
w0w, fantom написал про "замену" звуков и анимаций. Я знаю, что с помощью скриптинга можно включать/выключать многое, но чтобы менять то, что на прямую не зависит от кода :scratch_one-s_head:Т.к. не разбираюсь в PAWN'е, многого написать не могу.
По поводу замены звуков модели в .qc файле:
Вызываем событие, указываем на каком кадре должен проигрываться звук и путь до него.
Не прокатит на анимках выстрела. На остальном - пожалуйста.
 
Сообщения
2,143
Реакции
1,225
Помог
44 раз(а)
fantom, кстати, при таком способе блокировки перезарядки, ломаются анимации на дробовиках.
 
Сообщения
2,491
Реакции
2,794
Помог
61 раз(а)
Minni, на дробиках не тестировал. Но в теме есть способ от KOBRA. Возможно его вариант лучше
 
Сообщения
2,143
Реакции
1,225
Помог
44 раз(а)
fantom, ну, я так, для баг репорта. Вдруг решишь допилить этот пример)
 

ArKaNeMaN

Квалифицированный специалист по VipModular
Сообщения
436
Реакции
297
Помог
5 раз(а)
Начал делать такое вот чудо https://github.com/ArKaNeMaN/amxx-CustomWeaponsAPI
Часть моментов брал от сюда, что-то от себя

Скорее всего будут какие-то косяки с ножами и дробовиками. Позже постараюсь поправить...
И ещё не все задумки из этой темы реализованы

Догадываюсь шо тут куча неоптимизированной хрени и надеюсь на хоть какую-то критику, которая поможет улучшить качество кода :))

C++:
#include <amxmodx>
#include <reapi>
#include <hamsandwich>
#include <json>

#pragma semicolon 1

#define DEBUG // Закомментировать чтобы запретить бесплатную выдачу пушек

#define WEAPONS_IMPULSE_OFFSET 4354
#define GetWeapFullName(%0) fmt("weapon_%s",%0)
#define json_object_get_type(%0,%1) json_get_type(json_object_get_value(%0,%1));
#define CUSTOM_WEAPONS_COUNT ArraySize(CustomWeapons)
#define GetWeapId(%0) get_entvar(%0,var_impulse)-WEAPONS_IMPULSE_OFFSET
#define IsCustomWeapon(%0) (0 <= %0 < CUSTOM_WEAPONS_COUNT)


enum E_Fwds{
    Fwd_LoadWeapon,
}

enum E_WeaponModels{
    WM_V[PLATFORM_MAX_PATH],
    WM_P[PLATFORM_MAX_PATH],
    WM_W[PLATFORM_MAX_PATH],
}

//enum E_WeaponEvents{
//    WH_Shot = 1,
//    WH_Reload,
//    WH_Deploy,
//    WH_Holster,
//    WH_Damage,
//}

//enum E_CustomHandlerData{
//    CHD_Plugin[64],
//    CHD_Function[64],
//}

enum E_WeaponSounds{
    WS_Shot[PLATFORM_MAX_PATH],
    WS_ShotSilent[PLATFORM_MAX_PATH], // Only M4A1 & USP-S
}

enum _:E_WeaponData{
    WD_Name[32],
    WD_DefaultName[32],
    WD_Models[E_WeaponModels],
    WD_Sounds[E_WeaponSounds],
    WD_ClipSize,
    WD_MaxAmmo,
    Float:WD_MaxWalkSpeed,
    WD_Weight,
    //Array:WD_CustomHandlers[E_WeaponEvents],
    Float:WD_DamageMult,
    WD_Price,
    Float:WD_Accuracy,
}

new Trie:WeaponsNames;
new Array:CustomWeapons;

new const PLUG_NAME[] = "Custom Weapons API";
new const PLUG_VER[] = "0.1";

public plugin_init(){
    register_plugin(PLUG_NAME, PLUG_VER, "ArKaNeMaN");
  
    RegisterHookChain(RG_CWeaponBox_SetModel , "Hook_WeaponBoxSetModel", false);
    RegisterHookChain(RG_CBasePlayer_SetAnimation , "Hook_PlayerAnimation", true);

    register_clcmd("CWAPI_Buy", "Cmd_Buy");
    #if defined DEBUG
        register_clcmd("CWAPI_Give", "Cmd_GiveCustomWeapon");
    #endif

    server_print("[%s v%s] loaded.", PLUG_NAME, PLUG_VER);
}

public plugin_precache(){
    LoadWeapons();
}

//public plugin_natives(){
//    // Регистрация обработчика события оружия по его имени
//    // Возвращает ID зарегистрированного обработчика
//    register_native("CWAPI_RegisterHook", "Native_RegisterHook");
//}

//public Native_RegisterHook(const PluginId, const Params){
//    static WeaponName[32]; get_string(1, WeaponName, charsmax(WeaponName));
//    static E_WeaponEvents:Event; Event = E_WeaponEvents:get_param_byref(2);
//    static FuncName[64]; get_string(3, FuncName, charsmax(FuncName));
//    static PlugName[64]; get_plugin(PluginId, PlugName, charsmax(PlugName));
//    if(!TrieKeyExists(WeaponsNames, WeaponName)) return -1;
//    static WeaponId; TrieGetCell(WeaponsNames, WeaponName, WeaponId);
//    static Data[E_WeaponData]; ArrayGetArray(CustomWeapons, WeaponId, Data);
//    if(Data[WD_CustomHandlers][Event] == Invalid_Array) Data[WD_CustomHandlers][Event] = ArrayCreate(E_CustomHandlerData);
//    static Handler[E_CustomHandlerData];
//    formatex(Handler[CHD_Plugin], charsmax(Handler[CHD_Plugin]), PlugName);
//    formatex(Handler[CHD_Function], charsmax(Handler[CHD_Function]), FuncName);
//    static HandlerId; HandlerId = ArrayPushArray(Data[WD_CustomHandlers][Event], Handler);
//    ArraySetArray(CustomWeapons, WeapnId, Data);
//    return HandlerId;
//}
//
//CallWeaponFwd(const WeaponId, const E_WeaponEvents:Event){
//    static Data[E_WeaponData]; ArrayGetArray(CustomWeapons, WeaponId, Data);
//
//    static Handler[E_CustomHandlerData];
//    for(new i = 0; i < ArraySize(Data[WD_CustomHandlers][Event]); i++){
//        ArrayGetArray(Data[WD_CustomHandlers][Event], i, Handler);
//
//        callfunc_begin(Handler[CHD_Function], Handler[CHD_Plugin]);
//
//        call
//
//        callfunc_end();
//    }
//}

public Hook_WeaponBoxSetModel(const WeaponBox){
    static ItemId;
    if(!(ItemId = GetItemFromWeaponBox(WeaponBox))) return HC_CONTINUE;
    static WeaponId; WeaponId = GetWeapId(ItemId);
    if(!IsCustomWeapon(WeaponId)) return HC_CONTINUE;
    static Data[E_WeaponData]; ArrayGetArray(CustomWeapons, WeaponId, Data);
    if(Data[WD_Models][WM_W][0]) SetHookChainArg(2, ATYPE_STRING, Data[WD_Models][WM_W], PLATFORM_MAX_PATH-1);
    return HC_SUPERCEDE;
}

public Hook_PlayerAnimation(const Id, const PLAYER_ANIM:Anim){
    if(!is_user_connected(Id)) return;
    if(Anim != PLAYER_ATTACK1) return;
    static ItemId; ItemId = get_member(Id, m_pActiveItem);
    static WeaponId; WeaponId = GetWeapId(ItemId);
    if(!IsCustomWeapon(WeaponId)) return;
    static Data[E_WeaponData]; ArrayGetArray(CustomWeapons, WeaponId, Data);
  
    // Звук вроде бы слышен только носителю
    if(IsWeaponSilenced(ItemId)) if(Data[WD_Sounds][WS_ShotSilent][0]) rh_emit_sound2(Id, 0, CHAN_WEAPON, Data[WD_Sounds][WS_ShotSilent]);
    else if(Data[WD_Sounds][WS_Shot][0]) rh_emit_sound2(Id, 0, CHAN_WEAPON, Data[WD_Sounds][WS_Shot]);
}

#if defined DEBUG
    public Cmd_GiveCustomWeapon(const Id){
        static WeaponName[32]; read_argv(1, WeaponName, charsmax(WeaponName));
        if(TrieKeyExists(WeaponsNames, WeaponName)){
            static WeaponId; TrieGetCell(WeaponsNames, WeaponName, WeaponId);
            if(GiveCustomWeapon(Id, WeaponId) != -1) client_print_color(Id, print_team_default, "^3Вы взяли ^4%s", WeaponName);
            else client_print_color(Id, print_team_default, "^3При выдаче возникла ошибка");
            return PLUGIN_HANDLED;
        }
        client_print_color(Id, print_team_default, "^3Оружие ^4%s ^3не найдено", WeaponName);
        return PLUGIN_CONTINUE;
    }
#endif

public Cmd_Buy(const Id){
    if(!IsUserInBuyZone(Id)){
        client_print_color(Id, print_team_default, "^3Вы не в зоне покупки");
        return PLUGIN_HANDLED;
    }
    static WeaponName[32]; read_argv(1, WeaponName, charsmax(WeaponName));
    if(!TrieKeyExists(WeaponsNames, WeaponName)) return PLUGIN_CONTINUE;
    static WeaponId; TrieGetCell(WeaponsNames, WeaponName, WeaponId);
    static Data[E_WeaponData]; ArrayGetArray(CustomWeapons, WeaponId, Data);
    if(!Data[WD_Price]){
        client_print_color(Id, print_team_default, "^3Оружие ^4%s ^3нельзя купить", WeaponName);
        return PLUGIN_HANDLED;
    }
    if(get_member(Id, m_iAccount) < Data[WD_Price]){
        client_print_color(Id, print_team_default, "^3У вас недостаточно средств для покупки ^4%s", WeaponName);
        return PLUGIN_HANDLED;
    }
    if(GiveCustomWeapon(Id, WeaponId) != -1){
        rg_add_account(Id, -Data[WD_Price], AS_ADD);
        client_print_color(Id, print_team_default, "^3Вы купили ^4%s ^3за ^4$%d", WeaponName, Data[WD_Price]);
    }
    else client_print_color(Id, print_team_default, "^3При покупке возникла ошибка");
    return PLUGIN_HANDLED;
}

public Hook_PlayerItemDeploy(const ItemId){
    if(!IsCustomWeapon(GetWeapId(ItemId))) return HAM_IGNORED;
    static Id; Id = get_member(ItemId, m_pPlayer);
    if(!is_user_connected(Id)) return HAM_IGNORED;
  
    static Data[E_WeaponData]; ArrayGetArray(CustomWeapons, GetWeapId(ItemId), Data);

    if(Data[WD_Models][WM_V][0]) set_entvar(Id, var_viewmodel, Data[WD_Models][WM_V][0]);
    if(Data[WD_Models][WM_P][0]) set_entvar(Id, var_weaponmodel, Data[WD_Models][WM_P][0]);

    return HAM_IGNORED;
}

//public Hook_PlayerItemHolster(const ItemId){
//    if(!IsCustomWeapon(GetWeapId(ItemId))) return HAM_IGNORED;
//    static Id; Id = get_member(ItemId, m_pPlayer);
//    if(!is_user_connected(Id)) return HAM_IGNORED;
//
//    return HAM_IGNORED;
//}
//
//public Hook_PlayerItemReloaded(const ItemId){
//    if(!IsCustomWeapon(GetWeapId(ItemId))) return HAM_IGNORED;
//    static Id; Id = get_member(ItemId, m_pPlayer);
//    if(!is_user_connected(Id)) return HAM_IGNORED;
//
//    return HAM_IGNORED;
//}

public Hook_PlayerGetMaxSpeed(const ItemId){
    if(!IsCustomWeapon(GetWeapId(ItemId))) return HAM_IGNORED;
    static Id; Id = get_member(ItemId, m_pPlayer);
    if(!is_user_connected(Id)) return HAM_IGNORED;
  
    static Data[E_WeaponData]; ArrayGetArray(CustomWeapons, GetWeapId(ItemId), Data);

    if(Data[WD_MaxWalkSpeed]){
        SetHamReturnFloat(Data[WD_MaxWalkSpeed]);
        return HAM_SUPERCEDE;
    }

    return HAM_IGNORED;
}

//public Cmd_ChooseCustomWeapon(const Id){
//    static Cmd[32]; read_argv(0, Cmd, charsmax(Cmd));
//    if(equal(Cmd, "weapon_", 7) && TrieKeyExists(WeaponsNames, Cmd[7])){
//        static WeaponId; TrieGetCell(WeaponsNames, Cmd[7], WeaponId);
//        static Data[E_WeaponData]; ArrayGetArray(CustomWeapons, WeaponId, Data);
//        engclient_cmd(Id, Data[WD_DefaultName]);
//    }
//}

GiveCustomWeapon(const Id, const WeaponId){
    if(!IsCustomWeapon(WeaponId)) return -1;

    new Data[E_WeaponData]; ArrayGetArray(CustomWeapons, WeaponId, Data);
    new ItemId = rg_give_custom_item(Id, GetWeapFullName(Data[WD_DefaultName]), GT_DROP_AND_REPLACE, WeaponId+WEAPONS_IMPULSE_OFFSET);

    if(is_nullent(ItemId)) return -1;

    static WeaponIdType:DefaultWeaponId; DefaultWeaponId = WeaponIdType:rg_get_iteminfo(ItemId, ItemInfo_iId);

    if(Data[WD_Weight]) rg_set_iteminfo(ItemId, ItemInfo_iWeight, Data[WD_Weight]);
  
    if(Data[WD_ClipSize]){
        rg_set_iteminfo(ItemId, ItemInfo_iMaxClip, Data[WD_ClipSize]);
        rg_set_user_ammo(Id, DefaultWeaponId, Data[WD_ClipSize]);
    }

    if(Data[WD_MaxAmmo]){
        rg_set_iteminfo(ItemId, ItemInfo_iMaxAmmo1, Data[WD_MaxAmmo]);
        rg_set_user_bpammo(Id, DefaultWeaponId, Data[WD_MaxAmmo]);
    }

    if(Data[WD_DamageMult]){
        set_member(ItemId, m_Weapon_flBaseDamage, Float:get_member(ItemId, m_Weapon_flBaseDamage)*Data[WD_DamageMult]);

        if(DefaultWeaponId == WEAPON_M4A1) set_member(ItemId, m_M4A1_flBaseDamageSil, Float:get_member(ItemId, m_M4A1_flBaseDamageSil)*Data[WD_DamageMult]);
        else if(DefaultWeaponId == WEAPON_USP) set_member(ItemId, m_USP_flBaseDamageSil, Float:get_member(ItemId, m_USP_flBaseDamageSil)*Data[WD_DamageMult]);
        else if(DefaultWeaponId == WEAPON_FAMAS) set_member(ItemId, m_Famas_flBaseDamageBurst, Float:get_member(ItemId, m_Famas_flBaseDamageBurst)*Data[WD_DamageMult]);
    }

    return ItemId;
}

// Получение ID итема из WeaponBox'а
GetItemFromWeaponBox(const WeaponBox){
    for(new i = 0, ItemId; i < MAX_ITEM_TYPES; i++){
        ItemId = get_member(WeaponBox, m_WeaponBox_rgpPlayerItems, i);
        if(!is_nullent(ItemId)) return ItemId;
    }
    return NULLENT;
}

// Надет ли глушитель
bool:IsWeaponSilenced(const ItemId){
    static WeaponState:State; State = get_member(ItemId, m_Weapon_iWeaponState);
    static bool:IsSilenced; IsSilenced = (State & WPNSTATE_USP_SILENCED || State & WPNSTATE_M4A1_SILENCED);
    return IsSilenced;
}

// В зоне закупки ли игрок
bool:IsUserInBuyZone(const Id){
    static Signal[UnifiedSignals]; get_member(Id, m_signals, Signal);
    return (Signal[US_Signal] == _:SIGNAL_BUY);

    //log_amx("IsUserInBuyZone signal: [signal => %d | state = %d] || SIGNAL_BUY = %d", Signal[US_Signal], Signal[US_State], _:SIGNAL_BUY);
    //return true;
}

// Загрузка пушек из кфг
LoadWeapons(){
    CustomWeapons = ArrayCreate(E_WeaponData);
    WeaponsNames = TrieCreate();
  
    new file[PLATFORM_MAX_PATH];
    get_localinfo("amxx_configsdir", file, charsmax(file));
    add(file, charsmax(file), "/plugins/CustomWeaponsAPI/Weapons.json");
    if(!file_exists(file)){
        set_fail_state("[ERROR] Config file '%s' not found", file);
        return;
    }
    new JSON:List = json_parse(file, true);
    if(!json_is_array(List)){
        json_free(List);
        set_fail_state("[ERROR] Invalid config structure. File '%s'", file);
        return;
    }
    new Data[E_WeaponData], JSON:Item;
    for(new i = 0; i < json_array_get_count(List); i++){
        Item = json_array_get_value(List, i);
        if(!json_is_object(Item)){
            json_free(Item);
            set_fail_state("[WARNING] Invalid config structure. File '%s'. Item #%d", file, i);
            continue;
        }

        json_object_get_string(Item, "Name", Data[WD_Name], charsmax(Data[WD_Name]));
        if(TrieKeyExists(WeaponsNames, Data[WD_Name])){
            json_free(Item);
            set_fail_state("[WARNING] Duplicate weapon name '%s'. File '%s'. Item #%d", Data[WD_Name], file, i);
            continue;
        }

        json_object_get_string(Item, "DefaultName", Data[WD_DefaultName], charsmax(Data[WD_DefaultName]));

        if(json_object_has_value(Item, "Models", JSONObject)){
            new JSON:Models = json_object_get_value(Item, "Models");

            json_object_get_string(Models, "v", Data[WD_Models][WM_V], PLATFORM_MAX_PATH-1);
            if(file_exists(Data[WD_Models][WM_V])) precache_model(Data[WD_Models][WM_V]);
            else formatex(Data[WD_Models][WM_V], PLATFORM_MAX_PATH-1, "");

            json_object_get_string(Models, "p", Data[WD_Models][WM_P], PLATFORM_MAX_PATH-1);
            if(file_exists(Data[WD_Models][WM_P])) precache_model(Data[WD_Models][WM_P]);
            else formatex(Data[WD_Models][WM_P], PLATFORM_MAX_PATH-1, "");

            json_object_get_string(Models, "w", Data[WD_Models][WM_W], PLATFORM_MAX_PATH-1);
            if(file_exists(Data[WD_Models][WM_W])) precache_model(Data[WD_Models][WM_W]);
            else formatex(Data[WD_Models][WM_W], PLATFORM_MAX_PATH-1, "");
          
            json_free(Models);
        }

        if(json_object_has_value(Item, "Sounds", JSONObject)){
            new JSON:Sounds = json_object_get_value(Item, "Sounds");

            json_object_get_string(Sounds, "ShotSilent", Data[WD_Sounds][WS_ShotSilent], PLATFORM_MAX_PATH-1);
            if(file_exists(fmt("sound/%s", Data[WD_Sounds][WS_ShotSilent]))) precache_sound(Data[WD_Sounds][WS_ShotSilent]);
            else if(Data[WD_Sounds][WS_Shot][0]){
                log_amx("[WARNING] Sound file '%s' not found.", Data[WD_Sounds][WS_ShotSilent]);
                formatex(Data[WD_Sounds][WS_ShotSilent], PLATFORM_MAX_PATH-1, "");
            }

            json_object_get_string(Sounds, "Shot", Data[WD_Sounds][WS_Shot], PLATFORM_MAX_PATH-1);
            if(file_exists(fmt("sound/%s", Data[WD_Sounds][WS_Shot]))) precache_sound(Data[WD_Sounds][WS_Shot]);
            else if(Data[WD_Sounds][WS_Shot][0]){
                log_amx("[WARNING] Sound file '%s' not found.", Data[WD_Sounds][WS_Shot]);
                formatex(Data[WD_Sounds][WS_Shot], PLATFORM_MAX_PATH-1, "");
            }
          

            if(json_object_has_value(Sounds, "OnlyPrecache", JSONArray)){
                new JSON:OnlyPrecache = json_object_get_value(Sounds, "OnlyPrecache");
              
                new Temp[PLATFORM_MAX_PATH];
                for(new k = 0; k < json_array_get_count(OnlyPrecache); k++){
                    json_array_get_string(OnlyPrecache, k, Temp, PLATFORM_MAX_PATH-1);
                    if(file_exists(fmt("sound/%s", Temp))) precache_sound(Temp);
                    else log_amx("[WARNING] Sound file '%s' not found.", fmt("sound/%s", Temp));
                }

                json_free(OnlyPrecache);
            }

            json_free(Sounds);
        }

        Data[WD_ClipSize] = json_object_get_number(Item, "ClipSize");
        Data[WD_MaxAmmo] = json_object_get_number(Item, "MaxAmmo");
        Data[WD_Weight] = json_object_get_number(Item, "Weight");
        Data[WD_Price] = json_object_get_number(Item, "Price");

        Data[WD_MaxWalkSpeed] = json_object_get_real(Item, "MaxWalkSpeed");
        Data[WD_DamageMult] = json_object_get_real(Item, "DamageMult");
        Data[WD_Accuracy] = json_object_get_real(Item, "Accuracy");

        //register_clcmd(GetWeapFullName(Data[WD_Name]), "Cmd_ChooseCustomWeapon");

        RegisterHam(Ham_Item_Deploy, GetWeapFullName(Data[WD_DefaultName]), "Hook_PlayerItemDeploy", true);
        //RegisterHam(Ham_Item_Holster, GetWeapFullName(Data[WD_DefaultName]), "Hook_PlayerItemHolster", true);
        //RegisterHam(Ham_Weapon_Reload, GetWeapFullName(Data[WD_DefaultName]), "Hook_PlayerItemReloaded", false);
        RegisterHam(Ham_CS_Item_GetMaxSpeed, GetWeapFullName(Data[WD_DefaultName]), "Hook_PlayerGetMaxSpeed", false);
      
        TrieSetCell(WeaponsNames, Data[WD_Name], ArrayPushArray(CustomWeapons, Data));
        json_free(Item);
    }
    json_free(List);

    server_print("[%s v%s] %d custom weapons loaded from '%s'", PLUG_NAME, PLUG_VER, CUSTOM_WEAPONS_COUNT, file);
}
JSON:
[{
        "DefaultName": "deagle",
        "Name": "FireDeagle",
        "ClipSize": 5,
        "MaxAmmo": 20,
        "Models": {
            "v": "models/FireDeagle/v_deagle.mdl",
            "p": "models/FireDeagle/p_deagle.mdl",
            "w": "models/FireDeagle/w_deagle.mdl"
        },
        "Sounds": {
            "Shot": "FireDeagle/shoot.wav",
            "Reload": ""
        },
        "MaxWalkSpeed": 800,
        "DamageMult": 1.5,
        "Weight": 10,
        "Price": 3000
    },
    {
        "DefaultName": "m4a1",
        "Name": "NoveskeDiplomat",
        "ClipSize": 35,
        "MaxAmmo": 150,
        "Models": {
            "v": "models/CustomWeapons/Noveske Diplomat/v_m4a1.mdl",
            "p": "models/CustomWeapons/Noveske Diplomat/p_m4a1.mdl",
            "w": "models/CustomWeapons/Noveske Diplomat/w_m4a1.mdl"
        },
        "Sounds": {
            "Shot": "CustomWeapons/Noveske Diplomat/m4a1_unsil-1.wav",
            "ShotSilent": "CustomWeapons/Noveske Diplomat/m4a1-1.wav",
            "OnlyPrecache": [
                "weapons/M4A1/Ripper/boltback.wav",
                "weapons/M4A1/Ripper/boltrelease.wav",
                "weapons/M4A1/Ripper/bullet.wav",
                "weapons/M4A1/Ripper/draw.wav",
                "weapons/M4A1/Ripper/inspect.wav",
                "weapons/M4A1/Ripper/magin.wav",
                "weapons/M4A1/Ripper/magout.wav",
                "weapons/M4A1/Ripper/magtap.wav",
                "weapons/M4A1/Ripper/siloff.wav",
                "weapons/M4A1/Ripper/silon.wav",
                "weapons/M4A1/Ripper/silpush.wav",
                "weapons/M4A1/Ripper/maghit.wav"
            ]
        },
        "MaxWalkSpeed": 800,
        "DamageMult": 1.1,
        "Weight": 100,
        "Price": 6000
    }
]

Upd:
Подумал шо надо бы дописать краткое описание этого плагина...
Плагин создаёт кастомные пушки с указанными в кфг параметрами (В примере конфига есть все параметры)
Ну и добавляет возможность покупать эти пушки всем игрокам, если указаны их цены
 
Последнее редактирование:

Garey

ninjaCow
Сообщения
443
Реакции
1,097
Помог
11 раз(а)
ArKaNeMaN т.е. посути это кастом скин (со звуками) а не кастом оружие? могу ли я сделать кастомный урон, изменить пробивную способность или физику снаряда с вашим плагином?) и планируется ли это добавить?
 

ArKaNeMaN

Квалифицированный специалист по VipModular
Сообщения
436
Реакции
297
Помог
5 раз(а)
посути это кастом скин (со звуками)
Можно использовать и для этого... Там в кфг есть параметр "Sounds" -> "OnlyPrecache" для звуков модели...
А вообще это именно кастомные пушки, ну а "степень кастомности" уже зависит от того как их настроить

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

физику снаряда
Ну это по моему уже слишком... Планирую добавить хуки событий для этих кастомных пушек... И через них наверн можно будет сделать подобное... Мб сам и сделаю пример такого плагина, но не факт шо хорошего качества :)

и планируется ли это добавить?
Получается шо выше уже ответил на этот вопрос
 
Сообщения
2,143
Реакции
1,225
Помог
44 раз(а)
ArKaNeMaN, не берите тупой привычки писать код в одну строчку. Это нечитабельный мусор.
 
Сообщения
95
Реакции
6
Помог
2 раз(а)
Пример кастомного ножа с доп функциями

Код:
#include <amxmodx>
#include <hamsandwich>
#include <reapi>

#define WEAPON_ID WEAPON_KNIFE // ID оружия
#define WEAPON_NAME "weapon_knife" // Название оружия
#define WEAPON_SPEED 270.0 // Скорость бега. Закомментировать если количество по умолчанию
#define WEAPON_GRAVITY 0.7 // Гравитация (1.0 == sv_gravity). Закомментировать если количество по умолчанию.
#define WEAPON_DAMAGE 3.0 // Множитель урона. Закомментировать если значение по умолчанию
#define WEAPON_SLOT KNIFE_SLOT
#define MODEL_V "" // Путь к модели V оружия.
#define MODEL_P "" // Путь к модель P оружия.

#define WEAPON_UID 444
#define ActiveWeapon(%0) get_member(%0, m_pActiveItem)
#define IsCustomWeapon(%1) bool:(get_entvar(%1, var_impulse) == WEAPON_UID)
#define IsUserValid(%0) (1 <= %0 <= MaxClients)
new bool:HasWeapon[MAX_PLAYERS + 1];

public plugin_precache() {
    precache_model(MODEL_V);
    precache_model(MODEL_P);
}

public plugin_init() {
      RegisterHookChain(RG_CBasePlayer_GiveDefaultItems, "CBasePlayer_GiveDefaultItems_Post", true);
      RegisterHam(Ham_Item_Deploy, WEAPON_NAME, "Item_Deploy_Post", true);
      RegisterHam(Ham_CS_Item_GetMaxSpeed, WEAPON_NAME, "CS_Item_GetMaxSpeed_Pre", false);
      RegisterHookChain(RG_CBasePlayer_Spawn, "CBasePlayer_Spawn_Post", true);
      RegisterHam(Ham_Item_Holster, WEAPON_NAME, "HookHolster", true);
      RegisterHookChain(RG_CBasePlayer_TakeDamage, "CBasePlayer_TakeDamage", false);
}

public client_putinserver(id) {
    HasWeapon[id] = false;
}

public CBasePlayer_GiveDefaultItems_Post(const id) {
      if (!HasWeapon[id]) {
            return HC_CONTINUE;
      }

      new item = getItem(id);
      if (!item) {
            return HC_CONTINUE;
      }

      set_entvar(item, var_impulse, WEAPON_UID);
      new activeItem = ActiveWeapon(id);
      if (item == activeItem) {
            set_entvar(id, var_gravity, WEAPON_GRAVITY);
      }
      return HC_CONTINUE;
}

public Item_Deploy_Post(weapon) {
      if (!IsCustomWeapon(weapon)) {
            return HAM_IGNORED;
      }
      new id = get_member(weapon, m_pPlayer);
      set_entvar(id, var_viewmodel, MODEL_V);
      set_entvar(id, var_weaponmodel, MODEL_P);
      set_entvar(id, var_gravity, WEAPON_GRAVITY);
      return HAM_IGNORED;
}

public HookHolster(weapon) {
      new id = get_member(weapon, m_pPlayer);
      if (!is_user_connected(id) || !IsCustomWeapon(weapon)) {
            return HAM_IGNORED;
      }
      set_entvar(id, var_gravity, 1.0);
      return HAM_IGNORED;
}

public CBasePlayer_Spawn_Post(const id) {
      if (!is_user_connected(id)) {
            return HC_CONTINUE;
      }

      new item = get_member(id, m_pActiveItem);
      if (!is_nullent(item) && IsCustomWeapon(item)) {
            set_entvar(id, var_gravity, WEAPON_GRAVITY);
      }
      return HC_CONTINUE;
}

public CS_Item_GetMaxSpeed_Pre(const weapon) {
    if (IsCustomWeapon(weapon)) {
        SetHamReturnFloat(WEAPON_SPEED);
        return HAM_SUPERCEDE;
    }

    return HAM_IGNORED;
}

public CBasePlayer_TakeDamage(const iVictim, iInflictor, iAttacker, Float:flDamage, iBitsDamageType)
{
    if(!is_user_connected(iAttacker) || iVictim == iAttacker || iInflictor != iAttacker){
        return HC_CONTINUE;
    }
    new weapon = ActiveWeapon(iAttacker)
    if(!IsCustomWeapon(weapon)){
        return HC_CONTINUE;
    }
    SetHookChainArg(4, ATYPE_FLOAT, flDamage*WEAPON_DAMAGE);
    return HC_CONTINUE;
}

getItem(const id) {
      new item = get_member(id, m_rgpPlayerItems, WEAPON_SLOT);
      while (item) {
            if (get_member(item, m_iId) == WEAPON_ID) {
                  return item;
            }

            item = get_member(item, m_pNext);
      }
      return 0;
}

public plugin_natives()
{
        register_native("CustomWeaponKnife",    "__CustomWeaponKnife");
}

public __CustomWeaponKnife(iPlugin, iParams)
{
    enum { player = 1 };

    new id = get_param(player);
    if(is_user_connected(id)) {
            rg_remove_items_by_slot(id, WEAPON_SLOT)
            new item = rg_give_custom_item(id, WEAPON_NAME, GT_REPLACE, WEAPON_UID);
            if (!is_nullent(item)) {
                  HasWeapon[id] = true;
            }
      }
}
Спасибо fantom и w0w за помощь
 
Последнее редактирование:
Сообщения
38
Реакции
29
Помог
4 раз(а)
Skiptik, #define WEAPON_DAMAGE 3.0 // Скорость бега. Закоментировать если количество по умолчанию :crazy:
 
Последнее редактирование модератором:
Сообщения
2,143
Реакции
1,225
Помог
44 раз(а)
Skiptik, "количество"? Может быть "значение"? ?
 
Сообщения
188
Реакции
11
Первый пост актуальный сейчас ? Это для каждого оружия надо отдельный плагин ставить верно?
 

ArKaNeMaN

Квалифицированный специалист по VipModular
Сообщения
436
Реакции
297
Помог
5 раз(а)
Это для каждого оружия надо отдельный плагин ставить верно?
Да

Первый пост актуальный сейчас ?
Не совсем... Дальше есть более функциональные варианты
Вот вроде как последний вариант
https://dev-cs.ru/threads/1983/post-51400

Есть ещё такое, но не знаю на сколько этот вариант оптимизирован :)
https://github.com/ArKaNeMaN/amxx-CustomWeaponsAPI
(Тут не надо создавать отдельный плагин для каждой пушки и все параметры настраиваются в конфиге)
 
Последнее редактирование:

Пользователи, просматривающие эту тему

Сейчас на форуме нет ни одного пользователя.
Сверху Снизу