[GRENADE] Molotov and etc.

Сообщения
133
Реакции
441
Помог
2 раз(а)
Приветствую всех кто зашел на огонек. Одним словом - накодился! Поэтому сразу к делу. Критику, споры, предложения и так далее в мой адрес можете не высказывать ибо выкладываю я это для энтузиастов, и людей которые захотят в дальнейшем форкнуть, переписать - полностью или частично, или просто из-за существования данной тему, сделать\выложить уже свою работу -_- . Я буду рад если это кому-то поможет, и надеюсь найдется тот, кто все-таки форкнет данные наработки и сделает нормальный релиз с полностью рабочими механиками.

Сразу скажу что, код собирал из всяких кусков которые были доступны мне, где-то пытался написать что-то сам, где-то просил помощи, где-то колхозил, но вышло то что, вышло.

Хочу извиниться перед теми кому это не понравится и выразить благодарность всем кто как либо мог на это повлиять, и повлиял, и кого не будет в списке - Gracias. В частности могу выразить благодарности таким людям как: fantom, Garey, Denzer, Shel, OLOF, SISA, wopox1337, fl0wer, Xelson - каждый из них точно знает за что они достойны признания, в отличии от меня с плашкой скриптер :]

Весь код с комментариями (просьба отнестись с рофляной и пониманием, что я ненавижу писать todo`шки) и неисправностями в наличии, все ресурсы буду находиться в 1 архиве.

Начнем с молотова:

Мини видео презентация коктейля молотова.

Естественно вся реализация была успешна украдена у СИСЫ, а по другому и не могло быть. Ну и за основу я взял конечно же хилку фантома (ведь у меня не хватило мозгов даже нормально заюзать API кастом гранат)

В последних идеях было:
  • Разгорание по большей площади со временем
  • Нанесение урона в зависимости от наличия армора, а так же времени пребывания в радиусе горения.
  • Более лучшая визуализация эффектов чем сейчас [улучшить тайминги\плавности - появления\затухания, разброс частиц по осям, их размер, кучность, детализация, фреимрейт....]

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

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

К самому сладкому: как же завести модель горящего огня на земле. ( К слову, чтобы не возиться с формулами, я просто изменил модель на 3 бодигруппы по 50 кадров, и кручу верчу ими). Для того чтобы мы могли установить var_body больше 255, идем в файлик (на сервере) delta.lst, и меняем все что связано с body с 8 бит на 32 - DEFINE_DELTA( body, DT_INTEGER, 32, 1.0 ),. Все теперь сервер может оправить клиенту число бади больше 255.

Код:
/*global todo *** какаято хуйня
+ Сделать нормально MuzzleFlash  с задержкой, и с таймингом синка на анимации. (мб стоком с параметрами)
- При взрыве создавать основной энтити таргет и на нем уже синком распологать эффекты дебриса по радиусу
+ эффекты дебриса и гроунд огней сделать отдельным синком а не глобальным Ham_Think (не вышло, для енв спрайта нужено)
- сделать удаление энтитей овнера отдельной функцией (для нативов, кастом смока, еще чегото) - !destroyNade
- добавить нативы?
- запрет покупки вне байзоны (либо не делать вовсе оставить на обрботчик другого плагина с выдачей через натив)
- сделать урон по радиусу и собственный тайминг для урона
-+ добавить тач для кастом смока (хуевенько еще)
+ Разобраться с установкой граунд модели огня а не спрайта на основную энтити

black lives matter
- избавиться от ненужных\лишних свойств энтитей по типу var_chane-ов и classname-ов
- cделать первый радиус урона, и через время наростить второй (аля КСГО) - с таким кодом как у меня можно тока пососать
+ Сделать Throw trail огня для фитиля world модели

% - изменить рандом на радиус выкладку модели и дербисы
: - заменить энтити на svc дербисы (хуево получается както тогда)
- - мб сделать мгновенную прорисовку в экслоде а не в синке через цикл
//маму и папу его все этих гранат )))

- чтобы моделька как у сисы заработала, в delta.lst увеличиваем body на 32 бита
-
*/

#include <amxmodx>
#include <fakemeta>
#include <hamsandwich>
#include <reapi>
#include <xs>

#define PLUGIN_NAME "[GRENADE] Molotov"
#define PLUGIN_VERSION "1.0"
#define PLUGIN_AUTHOR "medusa"

//const Float:MOLOTOV_RADIUS = 150.0; //Радиус
const Float:MOLOTOV_THROWTIME = 2.0; //Время молотова в полете перед детонацией
const MOLOTOV_DURATION = 12; //20 sec
const Float:MOLOTOV_PLAYTHINK_TIME = 0.04;

new const MOLOTOV_FIRE_CLASSNAME[] = "custom_molotov";
new const EFFECT_CLASSNAME_MUZZLEFLASH[] = "weapon_molotov_muzzleflash";
new const EFFECT_CLASSNAME_WICK[] = "weapon_molotov_wick";
new const SMOKE_CLASSNAME_OWNER[] = "custom_smoke_owner";

const WeaponIdType:WEAPON_ID = WEAPON_SMOKEGRENADE;
const WeaponIdType:WEAPON_NEW_ID = WEAPON_GLOCK;
const WeaponIdType:WEAPON_FAKE_ID = WeaponIdType:75;
new const WEAPON_NAME[] = "weapon_smokegrenade";
new const AMMO_NAME[] = "Molotov";
new const WEAPON_NEW_NAME[] = "/grenaderad/weapon_molotov";
new const ITEM_CLASSNAME[] = "weapon_molotov";
new const GRENADE_CLASSNAME[] = "molotov";
const AMMO_ID = 16;


//const OBJECT_MOLOTOV_FIRE = 5123;

new MsgIdWeaponList, MsgIdAmmoPickup;
#if WEAPON_NEW_ID != WEAPON_GLOCK
new FwdRegUserMsg, MsgHookWeaponList;
#endif

new SpriteFireColumn, SpriteFireExplode, SpriteFireBall;//, SpriteFireGround;, SpriteBeamDisc;
new bool:bCreate[MAX_PLAYERS + 1];
new sizes[] = {51,51,51}, count = 3;

new const WEAPON_MODEL_VIEW_MOLOTOV[] = "models/grenaderad/v_molotov.mdl";
new const WEAPON_MODEL_PLAYER_MOLOTOV[] = "models/grenaderad/p_molotov.mdl";
new const WEAPON_MODEL_WORLD_MOLOTOV[] = "models/grenaderad/w_molotov.mdl";

new const MOLOTOV_MODEL_FLOOR[] = "models/grenaderad/molotov_fire_floor.mdl";

new const MOLOTOV_SPRITE_FIRE_BALL[] = "sprites/grenaderad/molotov_fire_ball.spr";
new const MOLOTOV_SPRITE_FIRE_COLUMN[] = "sprites/grenaderad/molotov_fire_column.spr";
new const MOLOTOV_SPRITE_FIRE_EXPLODE[] = "sprites/grenaderad/molotov_fire_explode_c.spr";
new const MOLOTOV_SPRITE_FIRE_GROUND[] = "sprites/grenaderad/molotov_fire_ground.spr";
new const MOLOTOV_SPRITE_XPARK1[] = "sprites/grenaderad/molotov_fire_blend_c.spr";
new const MOLOTOV_SPRITE_WICK[] = "sprites/grenaderad/molotov_wick.spr";

new const MOLOTOV_SOUND_EXPLODE[] = "weapons/grenaderad/molotov_explode.wav";
new const MOLOTOV_SOUND_EXPLODE2[] = "weapons/grenaderad/molotov_explode2.wav";
new const MOLOTOV_SOUND_HIT[] = "weapons/grenaderad/molotov_hit.wav";
new const MOLOTOV_SOUND_HIT2[] = "weapons/grenaderad/molotov_hit2.wav";
new const MOLOTOV_SOUND_IDLE[] = "weapons/grenaderad/molotov_idle_loop.wav";
new const MOLOTOV_SOUND_LOOP[] = "weapons/grenaderad/molotov_fire_ground.wav";
new const MOLOTOV_SOUND_FADEOUT[] = "weapons/grenaderad/molotov_fire_fadeout.wav";
new const MOLOTOV_SOUND_EXT[] = "weapons/grenaderad/molotov_extinguish.wav";

public plugin_precache() {
    precache_generic("sprites/grenaderad/weapon_molotov.txt");
    precache_generic("sprites/grenaderad/hud_molotov.spr");

    precache_model(WEAPON_MODEL_VIEW_MOLOTOV);
    precache_model(WEAPON_MODEL_PLAYER_MOLOTOV);
    precache_model(WEAPON_MODEL_WORLD_MOLOTOV);

#if WEAPON_NEW_ID != WEAPON_GLOCK
    MsgIdWeaponList = get_user_msgid("WeaponList");
    if (MsgIdWeaponList) {
        MsgHookWeaponList = register_message(MsgIdWeaponList, "HookWeaponList");
    } else {
        FwdRegUserMsg = register_forward(FM_RegUserMsg, "RegUserMsg_Post", true);
    }
#endif
    precache_model(MOLOTOV_MODEL_FLOOR);
    /*SpriteFireGround = */precache_model(MOLOTOV_SPRITE_FIRE_GROUND);
    precache_model(MOLOTOV_SPRITE_XPARK1);
    precache_model(MOLOTOV_SPRITE_WICK);

    precache_sound(MOLOTOV_SOUND_EXPLODE);
    precache_sound(MOLOTOV_SOUND_EXPLODE2);
    precache_sound(MOLOTOV_SOUND_HIT);
    precache_sound(MOLOTOV_SOUND_HIT2);
    precache_sound(MOLOTOV_SOUND_IDLE);
    precache_sound(MOLOTOV_SOUND_LOOP);
    precache_sound(MOLOTOV_SOUND_FADEOUT);
    precache_sound(MOLOTOV_SOUND_EXT);

    SpriteFireBall = precache_model(MOLOTOV_SPRITE_FIRE_BALL);
    SpriteFireColumn = precache_model(MOLOTOV_SPRITE_FIRE_COLUMN);
    SpriteFireExplode = precache_model(MOLOTOV_SPRITE_FIRE_EXPLODE);
    //SpriteBeamDisc = precache_model("sprites/shockwave.spr");
}

public plugin_init() {
    register_plugin(PLUGIN_NAME, PLUGIN_VERSION, PLUGIN_AUTHOR);

    register_clcmd(WEAPON_NEW_NAME, "CmdSelect");

    register_clcmd("say 1", "@Command_Molotov"); //test

    RegisterHookChain(RG_CSGameRules_CleanUpMap, "CSGameRules_CleanUpMap_Post", true);
    RegisterHookChain(RG_CBasePlayer_GiveAmmo, "CBasePlayer_GiveAmmo_Pre", false);
    RegisterHookChain(RG_CBasePlayerWeapon_DefaultDeploy, "CBasePlayerWeapon_DefaultDeploy_Pre", false);

    RegisterHam(Ham_Item_Deploy, WEAPON_NAME, "Item_Deploy_Post", true);
    RegisterHam(Ham_Item_Holster, WEAPON_NAME, "Item_Holster_Post", true);
    RegisterHam(Ham_Weapon_PrimaryAttack, WEAPON_NAME, "Item_PrimaryAttack_Pre", false);

    RegisterHookChain(RG_CBasePlayer_ThrowGrenade, "CBasePlayer_ThrowGrenade_Pre", false);

    RegisterHam(Ham_Think, "env_sprite", "FireMolotov_Think_Post", true);

    MsgIdAmmoPickup = get_user_msgid("AmmoPickup");

#if WEAPON_NEW_ID == WEAPON_GLOCK
    MsgIdWeaponList = get_user_msgid("WeaponList");
    UTIL_WeapoList(
        MSG_INIT, 0,
        WEAPON_NEW_NAME,
        AMMO_ID, 1,
        -1, -1, GRENADE_SLOT, 4, WEAPON_NEW_ID,
        ITEM_FLAG_LIMITINWORLD | ITEM_FLAG_EXHAUSTIBLE
    );
#else
    if (FwdRegUserMsg) {
        unregister_forward(FM_RegUserMsg, FwdRegUserMsg, true);
    }
    unregister_message(MsgIdWeaponList, MsgHookWeaponList);
#endif
}

@Command_Molotov(id)
{
    giveNade(id);
    giveAmmo(id, 9, AMMO_ID, 10); //ammo - max
}

#if WEAPON_NEW_ID != WEAPON_GLOCK
public RegUserMsg_Post(const name[]) {
    if (strcmp(name, "WeaponList") == 0) {
        MsgIdWeaponList = get_orig_retval();
        MsgHookWeaponList = register_message(MsgIdWeaponList, "HookWeaponList");
    }
}

public HookWeaponList(const msg_id, const msg_dest, const msg_entity) {
    enum {
        arg_name = 1,
        arg_ammo1,
        arg_ammo1_max,
        arg_ammo2,
        arg_ammo2_max,
        arg_slot,
        arg_position,
        arg_id,
        arg_flags,
    };

    if (msg_dest != MSG_INIT || WeaponIdType:get_msg_arg_int(arg_id) != WEAPON_NEW_ID) {
        return PLUGIN_CONTINUE;
    }

    set_msg_arg_string(arg_name,WEAPON_NEW_NAME);
    set_msg_arg_int(arg_ammo1, ARG_BYTE, AMMO_ID);
    set_msg_arg_int(arg_ammo1_max, ARG_BYTE, 1);
    set_msg_arg_int(arg_ammo2, ARG_BYTE, -1);
    set_msg_arg_int(arg_ammo2_max, ARG_BYTE, -1);
    set_msg_arg_int(arg_slot, ARG_BYTE, _:GRENADE_SLOT - 1);
    set_msg_arg_int(arg_position, ARG_BYTE, 4);
    set_msg_arg_int(arg_flags, ARG_BYTE, ITEM_FLAG_LIMITINWORLD | ITEM_FLAG_EXHAUSTIBLE);

    return PLUGIN_CONTINUE;
}
#endif

public CmdSelect(const id) {
    if (!is_user_alive(id)) {
        return PLUGIN_HANDLED;
    }

    new item = rg_get_player_item(id, ITEM_CLASSNAME, GRENADE_SLOT);
    if (item != 0 && get_member(id, m_pActiveItem) != item) {
        rg_switch_weapon(id, item);
    }
    return PLUGIN_HANDLED;
}

public CSGameRules_CleanUpMap_Post() {
    new ent = rg_find_ent_by_class(NULLENT, GRENADE_CLASSNAME, false);
    while (ent > 0) {
        destroyNade(ent);
        ent = rg_find_ent_by_class(ent, GRENADE_CLASSNAME, false);
    }

    new MolotovFire = rg_find_ent_by_class(NULLENT, MOLOTOV_FIRE_CLASSNAME, false);
    while (MolotovFire > 0) {
        destroyNade(MolotovFire);
        MolotovFire = rg_find_ent_by_class(MolotovFire, MOLOTOV_FIRE_CLASSNAME, false);
    }
}

public CBasePlayer_GiveAmmo_Pre(const id, const amount, const name[]) {
    if (strcmp(name, AMMO_NAME) != 0) {
        return HC_CONTINUE;
    }

    giveAmmo(id, amount, AMMO_ID, 1);
    SetHookChainReturn(ATYPE_INTEGER, AMMO_ID);
    return HC_SUPERCEDE;
}


public CBasePlayerWeapon_DefaultDeploy_Pre(const item, const szViewModel[], const szWeaponModel[], const iAnim, const szAnimExt[], const skiplocal) {
    if (FClassnameIs(item, ITEM_CLASSNAME)) {
        SetHookChainArg(2, ATYPE_STRING, WEAPON_MODEL_VIEW_MOLOTOV);
        SetHookChainArg(3, ATYPE_STRING, WEAPON_MODEL_PLAYER_MOLOTOV);
    }

    new WeaponIdType:wid = WeaponIdType:rg_get_iteminfo(item, ItemInfo_iId);
    if (wid != WEAPON_ID && wid != WEAPON_FAKE_ID) {
        return HC_CONTINUE;
    }

    new lastItem = get_member(get_member(item, m_pPlayer), m_pLastItem);
    if (is_nullent(lastItem) || item == lastItem) {
        return HC_CONTINUE;
    }

    if (WeaponIdType:rg_get_iteminfo(lastItem, ItemInfo_iId) == WEAPON_ID) {
        SetHookChainArg(6, ATYPE_INTEGER, 0);
    }

    return HC_CONTINUE;
}

public Item_Deploy_Post(const item) { //Вытащил по команде
    if (WeaponIdType:rg_get_iteminfo(item, ItemInfo_iId) == WEAPON_FAKE_ID) {
        rg_set_iteminfo(item, ItemInfo_iId, WEAPON_ID);
    }

    new other = get_member(get_member(item, m_pPlayer), m_rgpPlayerItems, GRENADE_SLOT);
    while (!is_nullent(other)) {
        if (item != other && WeaponIdType:rg_get_iteminfo(other, ItemInfo_iId) == WEAPON_ID) {
            rg_set_iteminfo(other, ItemInfo_iId, WEAPON_FAKE_ID);
        }
        other = get_member(other, m_pNext);
    }
}

public Item_Holster_Post(const item) {
    new other = get_member(get_member(item, m_pPlayer), m_rgpPlayerItems, GRENADE_SLOT);
    while (!is_nullent(other)) {
        Molotov_DeleteMuzzleFlash(item);
        if (item != other && WeaponIdType:rg_get_iteminfo(other, ItemInfo_iId) == WEAPON_FAKE_ID) {
            rg_set_iteminfo(other, ItemInfo_iId, WEAPON_ID);
            //rh_emit_sound2(other, other, CHAN_WEAPON, MOLOTOV_SOUND_IDLE, 0.0, ATTN_NONE, SND_STOP);
        }
        other = get_member(other, m_pNext);
    }
}

public Item_PrimaryAttack_Pre(item)
{
    if(is_nullent(item)) return;

    new other = get_member(item, m_pPlayer);

    if(FClassnameIs(item, ITEM_CLASSNAME) && Float: get_member(item, m_flStartThrow) + 0.5 < get_gametime() && get_member(item, m_flStartThrow)){

        if(bCreate[other]){
            return;
        }

        if(!bCreate[other]){
            Molotov_CreateMuzzleFlash(item, other, MOLOTOV_SPRITE_FIRE_COLUMN, 200.0, 25.0, 0.028, 3);
            Molotov_CreateMuzzleFlash(item, other, MOLOTOV_SPRITE_FIRE_BALL, 180.0, 30.0, 0.035, 3);
            Molotov_CreateMuzzleFlash(item, other, MOLOTOV_SPRITE_FIRE_BALL, 250.0, 25.0, 0.026, 4);
            Molotov_CreateMuzzleFlash(item, other, MOLOTOV_SPRITE_XPARK1, 100.0, 1.0, 0.032, 4);
            //rh_emit_sound2(other, other, CHAN_WEAPON, MOLOTOV_SOUND_IDLE);
            bCreate[other] = true;
        }
    }

    if(FClassnameIs(item, ITEM_CLASSNAME) && !Float: get_member(item, m_flStartThrow)) {
        bCreate[other] = false;
    }

}

public CBasePlayer_ThrowGrenade_Pre(const id, const item, const Float:vecSrc[3], const Float:vecThrow[3], const Float:time, const const usEvent) {
    if (!FClassnameIs(item, ITEM_CLASSNAME)) {
        return HC_CONTINUE;
    }

    new grenade = throwNade(id, vecSrc, vecThrow, MOLOTOV_THROWTIME);
    SetHookChainReturn(ATYPE_INTEGER, grenade);

    Molotov_DeleteMuzzleFlash(item);

    return HC_SUPERCEDE;
}

public FireMolotov_Think_Post(iEntity)
{
    if(is_nullent(iEntity)) return;

    set_entvar(iEntity, var_nextthink, get_gametime() + 0.025); //Скорость синка
}

giveNade(const id) {
    new item = rg_get_player_item(id, ITEM_CLASSNAME, GRENADE_SLOT);
    if (item != 0) {
        giveAmmo(id, 1, AMMO_ID, 1);
        return item;
    }

    item = rg_create_entity(WEAPON_NAME, false);
    if (is_nullent(item)) {
        return NULLENT;
    }

    new Float:origin[3];
    get_entvar(id, var_origin, origin);
    set_entvar(item, var_origin, origin);
    set_entvar(item, var_spawnflags, get_entvar(item, var_spawnflags) | SF_NORESPAWN);

    set_member(item, m_Weapon_iPrimaryAmmoType, AMMO_ID);
    set_member(item, m_Weapon_iSecondaryAmmoType, -1);

    set_entvar(item, var_classname, ITEM_CLASSNAME);

    dllfunc(DLLFunc_Spawn, item);

    set_member(item, m_iId, WEAPON_NEW_ID);

    rg_set_iteminfo(item, ItemInfo_pszName, WEAPON_NEW_NAME);
    rg_set_iteminfo(item, ItemInfo_pszAmmo1, AMMO_NAME);
    rg_set_iteminfo(item, ItemInfo_iMaxAmmo1, 1);
    rg_set_iteminfo(item, ItemInfo_iId, WEAPON_FAKE_ID);
    rg_set_iteminfo(item, ItemInfo_iPosition, 4);
    rg_set_iteminfo(item, ItemInfo_iWeight, 1);

    dllfunc(DLLFunc_Touch, item, id);

    if (get_entvar(item, var_owner) != id) {
        set_entvar(item, var_flags, FL_KILLME);
        return NULLENT;
    }

    return item;
}

giveAmmo(const id, const amount, const ammo, const max) {
    if (get_entvar(id, var_flags) & FL_SPECTATOR) {
        return;
    }

    new count = get_member(id, m_rgAmmo, ammo);
    new add = min(amount, max - count);
    if (add < 1) {
        return;
    }

    set_member(id, m_rgAmmo, count + add, ammo);

    emessage_begin(MSG_ONE, MsgIdAmmoPickup, .player = id);
    ewrite_byte(ammo);
    ewrite_byte(add);
    emessage_end();
}

throwNade(const id, const Float:vecSrc[3], const Float:vecThrow[3], const Float:time) {
    new grenade = rg_create_entity("info_target", false);
    if (is_nullent(grenade)) {
        return 0;
    }

    set_entvar(grenade, var_classname, GRENADE_CLASSNAME);

    set_entvar(grenade, var_movetype, MOVETYPE_BOUNCE);
    set_entvar(grenade, var_solid, SOLID_BBOX);

    engfunc(EngFunc_SetOrigin, grenade, vecSrc);

    new Float:angles[3];
    get_entvar(id, var_angles, angles);
    set_entvar(grenade, var_angles, angles);

    set_entvar(grenade, var_owner, id);

    if (time < 0.1) {
        set_entvar(grenade, var_nextthink, get_gametime());
        set_entvar(grenade, var_velocity, Float:{0.0, 0.0, 0.0});
    } else {
        set_entvar(grenade, var_nextthink, get_gametime() + time);
        set_entvar(grenade, var_velocity, vecThrow);
    }

    set_entvar(grenade, var_animtime, get_gametime());
    set_entvar(grenade, var_sequence, random_num(1, 7));
    set_entvar(grenade, var_framerate, 1.0);
    set_entvar(grenade, var_gravity, 0.5);
    set_entvar(grenade, var_friction, 0.8);
    engfunc(EngFunc_SetModel, grenade, WEAPON_MODEL_WORLD_MOLOTOV);
    //set_entvar(grenade, var_dmg, 30.0);
    set_entvar(grenade, var_dmgtime, get_gametime() + time);
    set_entvar(grenade, var_nextthink, get_gametime() + 0.01);
 
    if (!is_nullent(grenade)) {
        Molotov_CreateWickFollow(grenade, MOLOTOV_SPRITE_WICK, 250.0, 25.0, 0.125, 1);
    }
 
    SetTouch(grenade, "GrenadeTouch");
    SetThink(grenade, "GrenadeThink");

    return grenade;
}


public GrenadeTouch(const grenade, const other) {

    if(is_nullent(grenade)) return;

    if(!is_nullent(other) && FClassnameIs(other, "func_breakable") && get_entvar(other, var_spawnflags) != SF_BREAK_TRIGGER_ONLY)
        dllfunc(DLLFunc_Use, other, grenade);
     
    if (!is_nullent(other) && FClassnameIs(other, SMOKE_CLASSNAME_OWNER))
    {
        //client_print(0, print_chat, "SMOKE TOUCH MOLOTOV");
        destroyNade(grenade);
        //rh_emit_sound2(this, 0, CHAN_STATIC, MOLOTOV_SOUND_EXT);
    }

    new iOwner = get_entvar(grenade, var_owner);
 
    if(!is_nullent(other) && ExecuteHam(Ham_IsPlayer, other)) //тут надо фикс по наклону сделать , чтобы приземление было вниз
    {
        ExecuteHamB(Ham_TakeDamage, other, grenade, iOwner, 2.0, DMG_GRENADE);
        set_entvar(grenade, var_dmgtime, 0.0);
        set_entvar(grenade, var_nextthink, get_gametime() + 0.01);

        return;
    }

    new Float: flFraction;

    new Float: vecOffset[6][3] =
    {
        { 0.0, 0.0, -1.0 }, { 0.0, 0.0, 1.0 }, { -1.0, 0.0, 0.0 },
        { 1.0, 0.0, 0.0 }, { 0.0, -1.0, 0.0 }, { 0.0, 1.0, 0.0 }
    };

    new Float: vecEnd[3];
    new Float: origin[3];
    new Float: vecPlaneNormal[3];

    get_entvar(grenade, var_origin, origin);

    for(new i = 0; i < 6; i++)
    {
        vecEnd[0] = origin[0] + vecOffset[i][0];
        vecEnd[1] = origin[1] + vecOffset[i][1];
        vecEnd[2] = origin[2] + vecOffset[i][2];

        engfunc(EngFunc_TraceLine, origin, vecEnd, IGNORE_MONSTERS, grenade, 0);

        get_tr2(0, TR_flFraction, flFraction);

        if(flFraction >= 1.0)
            continue;

        get_tr2(0, TR_vecPlaneNormal, vecPlaneNormal);

        if(vecPlaneNormal[2] >= 0.5)
        {
            set_entvar(grenade, var_dmgtime, 0.0);
            set_entvar(grenade, var_nextthink, get_gametime() + 0.01);
        }
        else
            rh_emit_sound2(grenade, 0, CHAN_VOICE, random_num(0, 1) ? MOLOTOV_SOUND_HIT : MOLOTOV_SOUND_HIT2);

        break;
    }
}

public GrenadeThink(const grenade) {
    if(is_nullent(grenade)) return;

    new Float: origin[3];
    get_entvar(grenade, var_origin, origin);

    if(engfunc(EngFunc_PointContents, origin) == CONTENTS_SKY )
    {
        set_entvar(grenade, var_flags, FL_KILLME);
        return;
    }

    set_entvar(grenade, var_nextthink, get_gametime() + 0.1);

    if(Float: get_entvar(grenade, var_dmgtime) > get_gametime())
        return;

    explodeNade(grenade);
}

explodeNade(const grenade) {
    if(is_nullent(grenade)) return;

    new Float: flFraction;

    new Float: vecEnd[3];
    new Float: origin[3];
    new Float: angles[3];

    get_entvar(grenade, var_origin, origin);
    get_entvar(grenade, var_angles, angles);

    vecEnd = origin;
    vecEnd[2] -= 64.0;

    engfunc(EngFunc_TraceLine, origin, vecEnd, IGNORE_MONSTERS, grenade, 0);
    get_tr2(0, TR_flFraction, flFraction);

    if(flFraction >= 1.0)
    {
        UTIL_CreateExplosion(origin, Float: { 0.0, 0.0, 20.0 }, SpriteFireExplode, 16, 20, TE_EXPLFLAG_NOSOUND | TE_EXPLFLAG_NOPARTICLES);
        //UTIL_CreateExplosion(origin, Float: { 0.0, 0.0, 20.0 }, SpriteFireBall, 14, 20, TE_EXPLFLAG_NOSOUND | TE_EXPLFLAG_NOPARTICLES);
        rh_emit_sound2(grenade, 0, CHAN_STATIC, MOLOTOV_SOUND_EXPLODE);

        //set_entvar(grenade, var_flags, FL_KILLME);
        destroyNade(grenade);

        return;
    }

    if(engfunc(EngFunc_PointContents, origin) == CONTENTS_WATER)
    {
        new dropgrenade = rg_create_entity("info_target", false);

        if(is_nullent(dropgrenade)) return;

        set_entvar(dropgrenade, var_classname, GRENADE_CLASSNAME);
        engfunc(EngFunc_SetModel, dropgrenade, WEAPON_MODEL_WORLD_MOLOTOV);
        //set_entvar(dropgrenade, var_body, 1);
        set_entvar(dropgrenade, var_sequence, 0);
        set_entvar(dropgrenade, var_movetype, MOVETYPE_TOSS);
        set_entvar(dropgrenade, var_solid, SOLID_TRIGGER);
        set_entvar(dropgrenade, var_velocity, Float:{0.0, 0.0, 0.0});
        engfunc(EngFunc_SetOrigin, dropgrenade, origin);
        set_entvar(dropgrenade, var_angles, angles);
        set_entvar(dropgrenade, var_owner, grenade);

        SetTouch(dropgrenade, "Drop_ItemMolotov_Touch");

        destroyNade(grenade);
        return;
    }

    //new owner = get_entvar(grenade, var_owner); // igrok kinuvshiy grenu

    new Float: vecEndPos[3];
    new Float: vecPlaneNormal[3];

    get_tr2(0, TR_vecEndPos, vecEndPos);
    get_tr2(0, TR_vecPlaneNormal, vecPlaneNormal);

    UTIL_CreateExplosion(origin, Float: { 0.0, 0.0, 0.0 }, SpriteFireExplode, 10, 20, TE_EXPLFLAG_NOSOUND | TE_EXPLFLAG_NOPARTICLES);
    //UTIL_BeamDisk(origin, SpriteBeamDisc, 1, 5, 5, 5, {0, 0, 80}, 200, 5, MOLOTOV_RADIUS);

    rh_emit_sound2(grenade, 0, CHAN_STATIC, MOLOTOV_SOUND_EXPLODE2);

    engfunc(EngFunc_VecToAngles, vecPlaneNormal, angles);

    for(new i = 0; i < 3; i++)
        origin[i] = vecEndPos[i] + vecPlaneNormal[i];

    new EntMolotovRadius = rg_create_entity("info_target");

    if (is_nullent(EntMolotovRadius))
        return;

    set_entvar(EntMolotovRadius, var_origin, origin);
    set_entvar(EntMolotovRadius, var_angles, angles);
    set_entvar(EntMolotovRadius, var_classname, MOLOTOV_FIRE_CLASSNAME);
    set_entvar(EntMolotovRadius, var_solid, SOLID_TRIGGER);
    set_entvar(EntMolotovRadius, var_movetype, MOVETYPE_TOSS); //тосс для детекта тригера
    //set_entvar(EntMolotovRadius, var_effects, EF_NODRAW)
    set_entvar(EntMolotovRadius, var_iuser2, get_gametime() + MOLOTOV_DURATION);
    set_entvar(EntMolotovRadius, var_fuser1, get_gametime() + 0.3);
    engfunc(EngFunc_SetOrigin, EntMolotovRadius, origin);
    engfunc(EngFunc_SetSize, EntMolotovRadius, Float:{-100.0, -100.0, -30.0}, Float:{100.0, 100.0, 30.0});

    set_entvar(EntMolotovRadius, var_nextthink, get_gametime() + MOLOTOV_PLAYTHINK_TIME);
 

    Molotov_CreateModelFloor(EntMolotovRadius, origin, angles,{1,15,30}, 1, 12);
    //suda random radius mini modelski seq 25-50 2-3 wtyki a potom v sinke half timer na razgoranie
 
    //Molotov_CreateDebris(EntMolotovRadius, origin);

    SetThink(EntMolotovRadius, "ThinkFire");
    SetTouch(EntMolotovRadius, "Molotov_TouchSmoke");

    //UTIL_CreateExplosion(origin, Float: { -10.0, 10.0, -50.0 }, SpriteFireBall, 6, 23,TE_EXPLFLAG_NODLIGHTS | TE_EXPLFLAG_NOSOUND | TE_EXPLFLAG_NOPARTICLES);

    //var_iuser1 = Номера энтити огня
    //var_iuser2 = тайм самого огня, надо проверку чтобы пока тайм не кончиться не удалять
    //var_fuser1 = тайм для UTIl эффектов
    //var_iuser3 = Количество моделей горения
    //rh_emit_sound2(MolotovFire, 0, CHAN_STATIC, SMOKE_SOUND);
    destroyNade(grenade);
}

public ThinkFire(EntMolotovRadius)
{
    if (is_nullent(EntMolotovRadius))
        return;

    static Float: origin[3];
    get_entvar(EntMolotovRadius, var_origin, origin);

    if(get_entvar(EntMolotovRadius, var_fuser1) <= get_gametime())
    {
        /*UTIL_CreateExplosion(origin, Float: { 10.0, 5.0, 20.0 }, SpriteFireBall, 5, 31, TE_EXPLFLAG_NODLIGHTS | TE_EXPLFLAG_NOSOUND | TE_EXPLFLAG_NOPARTICLES);
        UTIL_CreateExplosion(origin, Float: { 5.0, 10.0, 0.0 }, SpriteFireColumn, 4, 23, TE_EXPLFLAG_NODLIGHTS | TE_EXPLFLAG_NOSOUND | TE_EXPLFLAG_NOPARTICLES);
        UTIL_CreateExplosion(origin, Float: { 0.0, 0.0, 0.0 }, SpriteFireExplode, 5, 28, TE_EXPLFLAG_NODLIGHTS | TE_EXPLFLAG_NOSOUND | TE_EXPLFLAG_NOPARTICLES);
        UTIL_CreateExplosion(origin, Float: { -15.0, -15.0, -20.0 }, SpriteFireBall, 6, 31, TE_EXPLFLAG_NODLIGHTS | TE_EXPLFLAG_NOSOUND | TE_EXPLFLAG_NOPARTICLES);
        UTIL_CreateExplosion(origin, Float: { -10.0, -10.0, -35.0 }, SpriteFireColumn, 4, 23,TE_EXPLFLAG_NODLIGHTS | TE_EXPLFLAG_NOSOUND | TE_EXPLFLAG_NOPARTICLES);
        UTIL_CreateExplosion(origin, Float: { -10.0, 10.0, -50.0 }, SpriteFireBall, 6, 23,TE_EXPLFLAG_NODLIGHTS | TE_EXPLFLAG_NOSOUND | TE_EXPLFLAG_NOPARTICLES);*/
     
        UTIL_CreateExplosion(origin, Float: { 3.0, 3.0, 0.0 }, SpriteFireBall, 3, 20, TE_EXPLFLAG_NODLIGHTS | TE_EXPLFLAG_NOSOUND | TE_EXPLFLAG_NOPARTICLES);
        UTIL_CreateExplosion(origin, Float: { 6.0, 6.0, 0.0 }, SpriteFireColumn, 3, 20,TE_EXPLFLAG_NODLIGHTS | TE_EXPLFLAG_NOSOUND | TE_EXPLFLAG_NOPARTICLES);
        UTIL_CreateExplosion(origin, Float: { 0.0, 0.0, 0.0 }, SpriteFireBall, 5, 23,TE_EXPLFLAG_NODLIGHTS | TE_EXPLFLAG_NOSOUND | TE_EXPLFLAG_NOPARTICLES);

        set_entvar(EntMolotovRadius, var_fuser1, get_gametime() + random_float(0.35, 0.45));

    }
 
    new iFireNum = get_entvar(EntMolotovRadius, var_iuser3);
 
    if(iFireNum < 3 )
    {
        new Float: flFraction;

        new Float: vecStart[3];
        new Float: vecEnd[3];
        new Float: vecAngles[3];
        new Float: vecViewForward[3];
        new Float: vecPlaneNormal[3];

        get_entvar(EntMolotovRadius, var_vuser2, vecPlaneNormal);

        vecAngles[0] = random_float(-32.0, -128.0); //(-45.0, -135.0);
        vecAngles[1] = random_float(0.0, 360.0);
 
        engfunc(EngFunc_MakeVectors, vecAngles);
        global_get(glb_v_forward, vecViewForward);

        for(new i = 0; i < 3; i++)
        {
            vecStart[i] = origin[i] + vecPlaneNormal[i] * 32.0;
            vecEnd[i] = vecStart[i] + vecViewForward[i] * 128.0;
        }
         
        engfunc(EngFunc_TraceLine, vecStart, vecEnd, IGNORE_MONSTERS, EntMolotovRadius, 0);

        get_tr2(0, TR_flFraction, flFraction);
        get_tr2(0, TR_vecEndPos, vecEnd);
        get_tr2(0, TR_vecPlaneNormal, vecPlaneNormal);
     
        if(flFraction >= 1.0 || vecPlaneNormal[2] == -1.0) //flFraction >= 1.0
        {
            Molotov_CreateModelFloor(EntMolotovRadius, vecEnd, vecAngles,{1,15,30}, random_num(1,50) , random_num(3,8)); // random ili enum - {1,15,30}
            set_entvar(EntMolotovRadius, var_iuser3, iFireNum + 1);
            //client_print(0, print_chat, "num1 = %d",iFireNum);
        }
    }
 
    new iDebrisNum = get_entvar(EntMolotovRadius, var_iuser4);
 
    if(iDebrisNum < 40)
    {
        new Float: flFraction;

        new Float: vecStart[3];
        new Float: vecEnd[3];
        new Float: vecAngles[3];
        new Float: vecViewForward[3];
        new Float: vecPlaneNormal[3];

        get_entvar(EntMolotovRadius, var_vuser1, vecPlaneNormal);

        vecAngles[0] = random_float(-32.0, -128.0); //(-45.0, -135.0);
        vecAngles[1] = random_float(0.0, 360.0);
 
        engfunc(EngFunc_MakeVectors, vecAngles);
        global_get(glb_v_forward, vecViewForward);

        for(new i = 0; i < 3; i++)
        {
            vecStart[i] = origin[i] + vecPlaneNormal[i] * 32.0;
            vecEnd[i] = vecStart[i] + vecViewForward[i] * 128.0;
        }
        engfunc(EngFunc_TraceLine, vecStart, vecEnd, IGNORE_MONSTERS, EntMolotovRadius, 0);

        get_tr2(0, TR_flFraction, flFraction);
        get_tr2(0, TR_vecEndPos, vecEnd);
        get_tr2(0, TR_vecPlaneNormal, vecPlaneNormal);

        if(flFraction >= 1.0 || vecPlaneNormal[2] == -1.0)
        {
            set_entvar(EntMolotovRadius, var_iuser4, iDebrisNum + 1);
            //client_print(0, print_chat, "num2 = %i",iFireNum);
            Molotov_CreateDebris(EntMolotovRadius, vecEnd);
        }
    }

    new MolotovFire = MaxClients + 1;

    new Float:flDuration = get_entvar(EntMolotovRadius, var_iuser2);

    if (flDuration <= get_gametime())
    {
        set_entvar(EntMolotovRadius, var_nextthink, get_gametime() + MOLOTOV_PLAYTHINK_TIME);
        SetThink(EntMolotovRadius, "FireRemove");

        return;
    }

    while ((MolotovFire = rg_find_ent_by_class(MolotovFire, MOLOTOV_FIRE_CLASSNAME)))
    {
        if (get_entvar(MolotovFire, var_owner) != EntMolotovRadius)
            continue;

        new Float:flDuration = get_entvar(get_entvar(MolotovFire, var_iuser1), var_iuser2);

        new parts[3]; get_entvar(MolotovFire, var_vuser1, parts);

        if (flDuration >= get_gametime())
        for(new i = 0; i < count; i++)
        {
            parts[i]++;

            if(parts[i] > 50)
                parts[i] = 1;
        }
        else
        for(new i = 0; i < count; i++)
        {
            if(parts[i] > 0)
                parts[i]++;

            if(parts[i] > 50)
                parts[i] = 0;
        }

        set_entvar(MolotovFire, var_vuser1, parts);
        set_entvar(MolotovFire, var_body, CalculateModelBodyArr(parts, sizes, count));
    }

    set_entvar(EntMolotovRadius, var_nextthink, get_gametime() +  MOLOTOV_PLAYTHINK_TIME);
}


public FireRemove(EntMolotovRadius)
{
    if (is_nullent(EntMolotovRadius))
        return;

    new MolotovFire = MaxClients + 1;

    while ((MolotovFire = rg_find_ent_by_class(MolotovFire, MOLOTOV_FIRE_CLASSNAME)))
    {
        if (get_entvar(MolotovFire, var_owner) != EntMolotovRadius)
            continue;

        new parts[3]; get_entvar(MolotovFire, var_vuser1, parts);

        for(new i = 0; i < count; i++)
        {
            if(parts[i] > 0)
                parts[i]++;

            if(parts[i] > 50)
                parts[i] = 0;
        }

        set_entvar(MolotovFire, var_vuser1, parts);
        set_entvar(MolotovFire, var_body, CalculateModelBodyArr(parts, sizes, count));

        if((parts[0] | parts[1] | parts[2]) == 0 )
            set_entvar(MolotovFire, var_flags, FL_KILLME);
    }

    set_entvar(EntMolotovRadius, var_nextthink, get_gametime() + MOLOTOV_PLAYTHINK_TIME);
}


public Molotov_TouchSmoke(item, other)
{
    if(is_nullent(item) || is_nullent(other)) return;
 
    //set_entvar(item, var_nextthink, get_gametime() + 0.01);
 
    if (!is_nullent(other) && FClassnameIs(other, SMOKE_CLASSNAME_OWNER))
    {
        //client_print(0, print_chat, "TOUCH smoke");
        new MolotovFire = MaxClients + 1;

        while ((MolotovFire = rg_find_ent_by_class(MolotovFire, MOLOTOV_FIRE_CLASSNAME)))
        {
            if (get_entvar(MolotovFire, var_owner) != item)
                continue;

            set_entvar(MolotovFire, var_flags, FL_KILLME);
        }
     
        destroyNade(item);
        rh_emit_sound2(item, 0, CHAN_STATIC, MOLOTOV_SOUND_EXT);
        SetTouch(item, "");
    }

}

public Drop_ItemMolotov_Touch(item, other)
{
    if(is_nullent(item) || is_nullent(other)) return;

    if(!ExecuteHam(Ham_IsPlayer, other)) return;

    new ammo = rg_get_player_item(other, ITEM_CLASSNAME, GRENADE_SLOT);
    if(ammo != 0) return;

    giveNade(other);

    set_entvar(item, var_flags, FL_KILLME);
}

destroyNade(const grenade) {
    SetTouch(grenade, "");
    SetThink(grenade, "");
    set_entvar(grenade, var_flags, FL_KILLME);
 
    new item =  MaxClients + 1;

    while((item = rg_find_ent_by_class(item, EFFECT_CLASSNAME_WICK)))
    {
        if(get_entvar(item, var_owner) != grenade)
            continue;
         
        if(!is_nullent(item))
            set_entvar(item, var_flags, FL_KILLME);
    }
}


stock rg_get_player_item(const id, const classname[], const InventorySlotType:slot = NONE_SLOT) {
    new item = get_member(id, m_rgpPlayerItems, slot);
    while (!is_nullent(item)) {
        if (FClassnameIs(item, classname)) {
            return item;
        }
        item = get_member(item, m_pNext);
    }

    return 0;
}

stock UTIL_WeapoList(
    const type,
    const player,
    const name[],
    const ammo1,
    const maxAmmo1,
    const ammo2,
    const maxammo2,
    const InventorySlotType:slot,
    const position,
    const WeaponIdType:id,
    const flags
) {
    message_begin(type, MsgIdWeaponList, .player = player);
    write_string(name);
    write_byte(ammo1);
    write_byte(maxAmmo1);
    write_byte(ammo2);
    write_byte(maxammo2);
    write_byte(_:slot - 1);
    write_byte(position);
    write_byte(_:id);
    write_byte(flags);
    message_end();
}

/*stock UTIL_BeamDisk(const Float:origin[3], const sprite, const framerate, const life, const width, const amplitude, const color[3], const bright, const speed, const Float:size) {
    message_begin_f(MSG_BROADCAST, SVC_TEMPENTITY, origin, 0);
    write_byte(TE_BEAMDISK);
    write_coord_f(origin[0]);
    write_coord_f(origin[1]);
    write_coord_f(origin[2]);
    write_coord_f(origin[0]);
    write_coord_f(origin[1]);
    write_coord_f(origin[2] + size);
    write_short(sprite);
    write_byte(0);
    write_byte(framerate);
    write_byte(life);
    write_byte(width);
    write_byte(amplitude);
    write_byte(color[0]);
    write_byte(color[1]);
    write_byte(color[2]);
    write_byte(bright);
    write_byte(speed);
    message_end();
}*/

stock UTIL_CreateExplosion(const Float: origin[3], const Float: vecOriginOffset[3] = { 0.0, 0.0, 0.0 }, const isModelIndex, const iScale, const iFrameRate, const iFlags)
{
    message_begin_f(MSG_BROADCAST, SVC_TEMPENTITY, origin, 0);
    write_byte(TE_EXPLOSION);
    write_coord_f(origin[0] + vecOriginOffset[0]);
    write_coord_f(origin[1] + vecOriginOffset[1]);
    write_coord_f(origin[2] + vecOriginOffset[2]);
    write_short(isModelIndex);
    write_byte(iScale);
    write_byte(iFrameRate);
    write_byte(iFlags);
    message_end();
}

/*stock UTIL_Flame(const Float: origin[3], const isModelIndex)
{
    message_begin_f(MSG_BROADCAST, SVC_TEMPENTITY, origin, 0);
    write_byte(TE_SPRITE);
    write_coord_f(origin[0]);
    write_coord_f(origin[1]);
    write_coord_f(origin[2]);
    write_short(isModelIndex);
    write_byte(5);
    write_byte(255);
    message_end();
}*/



stock Molotov_CreateModelFloor(owner, Float: origin[3], Float: angles[3], parts[3], sequence, time )
{
    if(is_nullent(owner)) return;

    new Float: flFraction;

    new Float: vecEndPos[3];
    new Float: vecPlaneNormal[3];
    new Float: vecAngles[3];

    vecEndPos = origin;
    vecEndPos[2] -= 256.0;

    engfunc(EngFunc_TraceLine, origin, vecEndPos, IGNORE_MONSTERS, owner, 0);
    get_tr2(0, TR_flFraction, flFraction);

    if(flFraction >= 1.0)
        return;

    get_tr2(0, TR_vecEndPos, vecEndPos);
    get_tr2(0, TR_vecPlaneNormal, vecPlaneNormal);
    engfunc(EngFunc_VecToAngles, vecPlaneNormal, vecAngles);

    for(new i = 0; i < 3; i++)
        origin[i] = vecEndPos[i] + vecPlaneNormal[i];

    FloorOriginAngles(origin, angles);

    new MolotovFire = rg_create_entity("info_target", false);

    if(is_nullent(MolotovFire)) return;

    //new parts[3] = {1,15,30};
    set_entvar(MolotovFire, var_classname, MOLOTOV_FIRE_CLASSNAME);
    set_entvar(MolotovFire, var_owner, owner);
    engfunc(EngFunc_SetOrigin, MolotovFire, origin);
    engfunc(EngFunc_SetModel, MolotovFire, MOLOTOV_MODEL_FLOOR);
    set_entvar(MolotovFire, var_angles, angles);
    set_entvar(MolotovFire, var_sequence, sequence);
    set_entvar(MolotovFire, var_rendermode, kRenderTransAdd);
    set_entvar(MolotovFire, var_renderamt, 255.0);
    set_entvar(MolotovFire, var_vuser1, parts);
    set_entvar(MolotovFire, var_iuser1, MolotovFire);
    set_entvar(MolotovFire, var_iuser2, get_gametime() + time);

    dllfunc(DLLFunc_Spawn, MolotovFire);
}

stock Molotov_CreateDebris(owner, Float: origin[3])
{
    if(is_nullent(owner)) return;
    new Float: flFraction;
    //new Float: flCurTime = get_gametime();

    new Float: vecEndPos[3];
    new Float: vecPlaneNormal[3];
    new Float: vecAngles[3];

    vecEndPos = origin;
    vecEndPos[2] -= 256.0;

    engfunc(EngFunc_TraceLine, origin, vecEndPos, IGNORE_MONSTERS, owner, 0);
    get_tr2(0, TR_flFraction, flFraction);

    if(flFraction >= 1.0)
        return;

    get_tr2(0, TR_vecEndPos, vecEndPos);
    get_tr2(0, TR_vecPlaneNormal, vecPlaneNormal);
    engfunc(EngFunc_VecToAngles, vecPlaneNormal, vecAngles);

    for(new i = 0; i < 3; i++)
        origin[i] = vecEndPos[i] + vecPlaneNormal[i];

    vecAngles[0] = -vecAngles[0] + 180.0;
    vecAngles[2] = -vecAngles[2] + 180.0;

    new iFire = rg_create_entity("env_sprite", true);

    if(is_nullent(iFire))
        return;

    set_entvar(iFire, var_classname, MOLOTOV_FIRE_CLASSNAME);
    set_entvar(iFire, var_origin, origin);
    set_entvar(iFire, var_angles, vecAngles);
    set_entvar(iFire, var_model, MOLOTOV_SPRITE_FIRE_GROUND);
    set_entvar(iFire, var_spawnflags, SF_SPRITE_STARTON);
    //set_entvar(iFire, var_teleport_time, flCurTime + 10.0);
    set_entvar(iFire, var_owner, owner);
    set_entvar(iFire, var_rendermode, kRenderTransAdd);
    set_entvar(iFire, var_renderamt, 255.0);
    set_entvar(iFire, var_framerate, 12.0 );
    set_entvar(iFire, var_scale, 0.5);
    //set_entvar(iFire, var_nextthink, get_gametime() + 0.015);
    dllfunc(DLLFunc_Spawn, iFire);

    /*if(owner < MaxClients)
        set_entvar(iFire, var_vuser1, vecPlaneNormal);*/
}

stock Molotov_CreateMuzzleFlash(item, other, const models[], Float:renderamt, Float:frame, Float:scale, body)
{
    if(is_nullent(item)) return;

    new iMuzzleFlash = rg_create_entity("env_sprite", true);

    if(is_nullent(iMuzzleFlash)) return;

    set_entvar(iMuzzleFlash, var_model, models);
    set_entvar(iMuzzleFlash, var_classname, EFFECT_CLASSNAME_MUZZLEFLASH);
    set_entvar(iMuzzleFlash, var_spawnflags, SF_SPRITE_STARTON);
    set_entvar(iMuzzleFlash, var_rendermode, kRenderTransAdd);
    set_entvar(iMuzzleFlash, var_renderamt, renderamt);
    set_entvar(iMuzzleFlash, var_framerate, frame);
    set_entvar(iMuzzleFlash, var_scale, scale);
    set_entvar(iMuzzleFlash, var_owner, other);
    set_entvar(iMuzzleFlash, var_aiment, other);
    set_entvar(iMuzzleFlash, var_body, body); // аттач к фитилю кости в модельке ( 4- самый низ * 3 - середина * 2 - выше серидины *  1 -самое горлышко)
    dllfunc(DLLFunc_Spawn, iMuzzleFlash);
}

stock Molotov_CreateWickFollow(other, const models[], Float:renderamt, Float:frame, Float:scale, body)
{
    new iWickFollow = rg_create_entity("env_sprite", true);

    if(is_nullent(iWickFollow)) return;
 
    set_entvar(iWickFollow, var_model, models);
    //engfunc(EngFunc_SetModel, iWickFollow, models);
    set_entvar(iWickFollow, var_classname, EFFECT_CLASSNAME_WICK);
    set_entvar(iWickFollow, var_spawnflags, SF_SPRITE_STARTON);
    set_entvar(iWickFollow, var_rendermode, kRenderTransAdd);
    set_entvar(iWickFollow, var_renderamt, renderamt);
    set_entvar(iWickFollow, var_framerate, frame);
    set_entvar(iWickFollow, var_scale, scale);
    set_entvar(iWickFollow, var_owner, other);
    set_entvar(iWickFollow, var_aiment, other);
    set_entvar(iWickFollow, var_body, body);
    dllfunc(DLLFunc_Spawn, iWickFollow);
}

stock Molotov_DeleteMuzzleFlash(other)
{
    new item =  MaxClients + 1;

    while((item = rg_find_ent_by_class(item, EFFECT_CLASSNAME_MUZZLEFLASH)))
    {
        if(get_entvar(item, var_owner) != get_entvar(other, var_owner))
            continue;

        if(!is_nullent(item))
            set_entvar(item, var_flags, FL_KILLME);
    }
}

public CalculateModelBodyArr(const parts[], const sizes[],const count){//Если есть массив который нужно выбрать
    static bodyInt32 = 0, temp=0, it=0, tempCount;bodyInt32=0;tempCount = count;
    while (tempCount--){
        if (sizes[tempCount] == 1)continue;
        temp = parts[tempCount]; for (it=0;it<tempCount;it++)temp *= sizes[it];
        bodyInt32 += temp;
    }
    return bodyInt32;
}

new const Float:SubFloat[3] = {0.0, 0.0, 9999.0};
stock FloorOriginAngles(Float:flOrigin[3], Float:fAngles[3]){
    static Float:traceto[3], Float:fraction, Float:original_forward[3], Float:angles2[3], Float:right[3], Float:up[3], Float:fwd[3];
    new iTrace = create_tr2();if(!iTrace)return;
    xs_vec_sub(flOrigin, SubFloat, traceto);
    engfunc(EngFunc_TraceLine, flOrigin, traceto, IGNORE_MONSTERS|IGNORE_MISSILE, 0, iTrace);
    get_tr2(iTrace, TR_flFraction, fraction);
    if(fraction == 1.0){free_tr2(iTrace);return;}
    angle_vector(fAngles, ANGLEVECTOR_FORWARD, original_forward);
    get_tr2(iTrace, TR_vecPlaneNormal, up); free_tr2(iTrace);
    xs_vec_cross(original_forward, up, right);
    xs_vec_cross(up, right, fwd);
    vector_to_angle(fwd, fAngles);
    vector_to_angle(right, angles2);
    fAngles[2] = -1.0 * angles2[0];
}

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

Третьим плагином станет моя попытка модифицировать HE гранату, т.е. изменить эффекты взрыва и механику работы


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

Код:
/*
1. Физика полета гранаты -(говно с велосити)
2. Модель гранаты +
3. Нанесение урона себе *5 +
4. Нанесение урона союзникам *2 +
5. Нанесение урона за стену *5 +
6. Эффекты взрыва +
7. При попадание в игрока останавливается +

- хуета застревает на наклонных поверхностях надо нормальный троу сделать а не бомжатню.

*/

#include <amxmodx>
#include <fakemeta>
#include <hamsandwich>
#include <reapi>
#include <xs>

#define PLUGIN_NAME "[GRENADE] He Grenade"
#define PLUGIN_VERSION "1.0"
#define PLUGIN_AUTHOR "medusa"

const Float:THROWTIME = 1.7; //Время перед взрывом
const Float:EXLODE_RADIUS = 350.0
const Float:EXLODE_DEMAGE = 100.0

//new const GRENADE_CLASSNAME[] = "hegrenade";
const WeaponIdType:WEAPON_ID = WEAPON_HEGRENADE;

new SpriteFlareExplode, SpriteConcExplode, SpriteSmokeExplode, SpriteXparkExplode;
new HookChain:HookChain_CBasePlayer_TakeDamage;

new const GRENADE_VIEW_MODEL[] = "models/grenaderad/v_hegrenade.mdl";
new const GRENADE_PLAYER_MODEL[] = "models/grenaderad/p_hegrenade.mdl";
new const GRENADE_WORLD_MODEL[] = "models/grenaderad/w_hegrenade.mdl";

new const SPRITE_FLARE_EXPLODE[] = "sprites/grenaderad/hegrenade_explode.spr";
new const SPRITE_CONC_EXPLODE[] = "sprites/grenaderad/hegrenade_conc.spr"
new const SPRITE_SMOKE_EXPLODE[] = "sprites/grenaderad/hegrenade_smoke.spr"
new const SPRITE_XPARK_EXPLODE[] = "sprites/grenaderad/hegrenade_xpark.spr"

new const SOUND_HITWALL[] = "weapons/grenade_hit1.wav";

public plugin_precache()
{
    precache_model(GRENADE_VIEW_MODEL);
    precache_model(GRENADE_PLAYER_MODEL);
    precache_model(GRENADE_WORLD_MODEL);

    SpriteFlareExplode = precache_model(SPRITE_FLARE_EXPLODE);
    SpriteConcExplode = precache_model(SPRITE_CONC_EXPLODE);
    SpriteSmokeExplode = precache_model(SPRITE_SMOKE_EXPLODE);
    SpriteXparkExplode = precache_model(SPRITE_XPARK_EXPLODE);
 
    precache_sound(SOUND_HITWALL);
}

public plugin_init()
{
    register_plugin(PLUGIN_NAME, PLUGIN_VERSION, PLUGIN_AUTHOR);

    RegisterHookChain(RG_CBasePlayerWeapon_DefaultDeploy, "RG_CBasePlayerWeapon_DefaultDeploy_Pre", false);
    RegisterHookChain(RG_ThrowHeGrenade, "RG_ThrowHeGrenade_Pre", false);
 
    DisableHookChain((HookChain_CBasePlayer_TakeDamage = RegisterHookChain(RG_CBasePlayer_TakeDamage, "CBasePlayer_TakeDamage_Pre", false)));
}

public RG_CBasePlayerWeapon_DefaultDeploy_Pre(const this, szViewModel[], szWeaponModel[], iAnim, szAnimExt[], skiplocal)
{
    new WeaponIdType:wid = WeaponIdType:rg_get_iteminfo(this, ItemInfo_iId);
    if (wid == WEAPON_ID) {
        SetHookChainArg(2, ATYPE_STRING, GRENADE_VIEW_MODEL);
        SetHookChainArg(3, ATYPE_STRING, GRENADE_PLAYER_MODEL);
    }

    new lastItem = get_member(get_member(this, m_pPlayer), m_pLastItem);
    if (is_nullent(lastItem) || this == lastItem) {
        return HC_CONTINUE;
    }

    if (WeaponIdType:rg_get_iteminfo(lastItem, ItemInfo_iId) == WEAPON_ID) {
        SetHookChainArg(6, ATYPE_INTEGER, 0);
    }

    return HC_CONTINUE;
}

public RG_ThrowHeGrenade_Pre(const other, Float:vecStart[3], Float:vecVelocity[3], Float:time, const team, const usEvent) {
    new this = throwNade(other, vecStart, vecVelocity, THROWTIME);
    SetHookChainReturn(ATYPE_INTEGER, this);

    return HC_SUPERCEDE;
}

throwNade(const other, const Float:vecStart[3], const Float:vecVelocity[3], const Float:time) {
    new this = rg_create_entity("grenade", false);
    if (is_nullent(this)) {
        return 0;
    }

    //set_entvar(this, var_classname, GRENADE_CLASSNAME);

    set_entvar(this, var_movetype, MOVETYPE_BOUNCE);
    set_entvar(this, var_solid, SOLID_BBOX);

    engfunc(EngFunc_SetOrigin, this, vecStart);

    new Float:angles[3];
    get_entvar(other, var_angles, angles);
    set_entvar(this, var_angles, angles);

    set_entvar(this, var_owner, other);

    if (time < 0.1) {
        set_entvar(this, var_nextthink, get_gametime());
        set_entvar(this, var_velocity, Float:{0.0, 0.0, 0.0});
    } else {
        set_entvar(this, var_nextthink, get_gametime() + time);
        set_entvar(this, var_velocity, vecVelocity);
    }
    set_entvar(this, var_animtime, get_gametime());
    set_entvar(this, var_sequence, random_num(1,6));
    set_entvar(this, var_framerate, 1.0);
    set_entvar(this, var_gravity, 0.5);
    set_entvar(this, var_friction, 0.8);
    engfunc(EngFunc_SetModel, this, GRENADE_WORLD_MODEL);
    set_entvar(this, var_dmg, 100.0);
    set_entvar(this, var_dmgtime, get_gametime() + time);
    set_entvar(this, var_nextthink, get_gametime() + 0.1);

    SetTouch(this, "GrenadeTouch");
    SetThink(this, "GrenadeThink");

    return this;
}

public GrenadeThink(const this) {
    if (is_nullent(this))
        return;

    /*if(engfunc(EngFunc_PointContents, origin) == CONTENTS_SKY )
       {
            set_entvar(grenade, var_flags, FL_KILLME);
            return;
       }*/

    set_entvar(this, var_nextthink, get_gametime() + 0.1);

    if (Float: get_entvar(this, var_dmgtime) > get_gametime())
        return;

    explodeNade(this);
}

public GrenadeTouch(const this, const other) {

    if (is_nullent(this)) return;

    if (!is_nullent(other) && FClassnameIs(other, "func_breakable") && get_entvar(other, var_spawnflags) != SF_BREAK_TRIGGER_ONLY)
        dllfunc(DLLFunc_Use, other, this);
     
    new iOwner = get_entvar(this, var_owner);
 
    if (!is_nullent(other) && ExecuteHam(Ham_IsPlayer, other))
    {
        ExecuteHamB(Ham_TakeDamage, other, this, iOwner, 2.0, DMG_GRENADE);
        set_entvar(this, var_velocity, { 0.0, 0.0, 0.0 });
        set_entvar(this, var_solid, SOLID_NOT);
        SetTouch(this, "");
    }

    new Float: flFraction;

    new Float: vecOffset[6][3] =
    {
        { 0.0, 0.0, -1.0 }, { 0.0, 0.0, 1.0 }, { -1.0, 0.0, 0.0 },
        { 1.0, 0.0, 0.0 }, { 0.0, -1.0, 0.0 }, { 0.0, 1.0, 0.0 }
    }

    new Float: vecEnd[3];
    new Float: origin[3];
    new Float: vecPlaneNormal[3];

    get_entvar(this, var_origin, origin);

    for (new i = 0; i < 6; i++)
    {
        vecEnd[0] = origin[0] + vecOffset[i][0];
        vecEnd[1] = origin[1] + vecOffset[i][1];
        vecEnd[2] = origin[2] + vecOffset[i][2];

        engfunc(EngFunc_TraceLine, origin, vecEnd, IGNORE_MONSTERS, this, 0);

        get_tr2(0, TR_flFraction, flFraction);

        if (flFraction >= 1.0)
            continue;

        get_tr2(0, TR_vecPlaneNormal, vecPlaneNormal);
     
        new Float:vecVelocity[3];
        get_entvar(this, var_velocity, vecVelocity);

        vecVelocity[0] -=  vecVelocity[0] * 0.16;
        vecVelocity[1] -=  vecVelocity[1] * 0.16;
        vecVelocity[2] -=  vecVelocity[2] * 0.16;
     
        set_entvar(this, var_velocity, vecVelocity);

        if(vecPlaneNormal[2] > 0.8)
            set_entvar(this, var_sequence, 0);
     
        if (vecPlaneNormal[2] >= 0.5)
            set_entvar(this, var_nextthink, get_gametime() + 0.1);
        else
            rh_emit_sound2(this, 0, CHAN_VOICE, SOUND_HITWALL);

        break;
    }
}

explodeNade(const this) {
    if (is_nullent(this))
        return;

    new Float: origin[3];

    get_entvar(this, var_origin, origin);

    /*
    new Float: flFraction;
    new Float: vecEnd[3];
 
    vecEnd = origin;
    vecEnd[2] -= 64.0;

    engfunc(EngFunc_TraceLine, origin, vecEnd, IGNORE_MONSTERS, this, 0);
    get_tr2(0, TR_flFraction, flFraction);

    if(flFraction < 1.0)
        UTIL_CreateExplosion(origin, Float: { 0.0, 0.0, 10.0 }, SpriteFlareExplodeGround, 15, 25, TE_EXPLFLAG_NOSOUND | TE_EXPLFLAG_NOPARTICLES);*/

    UTIL_CreateExplosion(origin, Float: { 0.0, 0.0, 0.0 }, SpriteFlareExplode, 5, 30, TE_EXPLFLAG_NOPARTICLES);
    UTIL_CreateExplosion(origin, Float: { 0.0, 0.0, 0.0 }, SpriteXparkExplode, 10, 30,   TE_EXPLFLAG_NOSOUND | TE_EXPLFLAG_NOPARTICLES);
    UTIL_CreateSmoke(origin, Float: { 0.0, 0.0, 0.0 }, SpriteSmokeExplode, 25, 20);
    UTIL_CreateSmoke(origin, Float: { 0.0, 0.0, 0.0 }, SpriteConcExplode, 30, 35);

    new attacker = get_entvar(this, var_owner);

    EnableHookChain(HookChain_CBasePlayer_TakeDamage);
    rg_dmg_radius(origin, this, attacker, EXLODE_DEMAGE, EXLODE_RADIUS, 0, DMG_GRENADE);
    DisableHookChain(HookChain_CBasePlayer_TakeDamage);
     
    //rh_emit_sound2(this, 0, CHAN_STATIC, SOUND_EXPLODE2);
 
    UTIL_WorldDecal(origin);

    destroyNade(this);
}

public CBasePlayer_TakeDamage_Pre(const victim, pevInflictor, attacker, Float:flDamage, bitsDamageType)
{
    if (!is_user_connected(victim))
        return;

    if (!(bitsDamageType & DMG_GRENADE))
        return;
     
    if(bIsPenetrated(pevInflictor, victim))
        SetHookChainArg(4, ATYPE_FLOAT, flDamage * 0.5);
     
    new TeamName:attacker_team = get_member(attacker, m_iTeam);
     
    if (attacker == victim)
    {
        SetHookChainArg(4, ATYPE_FLOAT, flDamage * 0.5);
        return;
    }
     
    if(attacker_team == get_member(victim, m_iTeam))
    {
        SetHookChainArg(4, ATYPE_FLOAT, flDamage * 0.2);
        return;
    }
}

destroyNade(const this) {
    SetThink(this, "");
    SetTouch(this, "");
    set_entvar(this, var_flags, FL_KILLME);
}

stock UTIL_WorldDecal(Float:origin[3])
{
    message_begin(MSG_BROADCAST, SVC_TEMPENTITY);
    write_byte(TE_WORLDDECAL);
    write_coord_f(origin[0]);
    write_coord_f(origin[1]);
    write_coord_f(origin[2]);
    write_byte(engfunc( EngFunc_DecalIndex, "{oil1"));
    message_end();
}

stock UTIL_CreateSmoke(Float: vecOrigin[3], Float: vecOriginOffset[3] = { 0.0, 0.0, 0.0 }, isModelIndex, iScale, iFrameRate)
{
    message_begin_f(MSG_PVS, SVC_TEMPENTITY, vecOrigin, 0);
    write_byte(TE_SMOKE);
    write_coord_f(vecOrigin[0] + vecOriginOffset[0]);
    write_coord_f(vecOrigin[1] + vecOriginOffset[1]);
    write_coord_f(vecOrigin[2] + vecOriginOffset[2]);
    write_short(isModelIndex);
    write_byte(iScale);
    write_byte(iFrameRate);
    message_end();
}

stock UTIL_CreateExplosion(const Float: origin[3], const Float: vecOriginOffset[3] = { 0.0, 0.0, 0.0 }, const isModelIndex, const iScale, const iFrameRate, const iFlags)
{
    message_begin_f(MSG_PVS, SVC_TEMPENTITY, origin, 0);
    write_byte(TE_EXPLOSION);
    write_coord_f(origin[0] + vecOriginOffset[0]);
    write_coord_f(origin[1] + vecOriginOffset[1]);
    write_coord_f(origin[2] + vecOriginOffset[2]);
    write_short(isModelIndex);
    write_byte(iScale);
    write_byte(iFrameRate);
    write_byte(iFlags);
    message_end();
}

stock bool:bIsPenetrated(id, iKiller)
{
    static hTrace;
    if(!hTrace)
        hTrace = create_tr2();

    static Float:vfOrigin_Killer[3], Float:vfViewOfs[3];
    get_entvar(iKiller, var_origin, vfOrigin_Killer);
    get_entvar(iKiller, var_view_ofs, vfViewOfs);
    xs_vec_add(vfOrigin_Killer, vfViewOfs, vfOrigin_Killer);

    static Float:vfOrigin[3];
    get_entvar(id, var_origin, vfOrigin);
    get_entvar(id, var_view_ofs, vfViewOfs);
    xs_vec_add(vfOrigin, vfViewOfs, vfOrigin);

    engfunc(EngFunc_TraceLine, vfOrigin_Killer, vfOrigin, IGNORE_MONSTERS | IGNORE_GLASS, 0, hTrace);

    static Float:fFraction;
    get_tr2(hTrace, TR_flFraction, fFraction);

    return bool:(fFraction != 1.0);
}

В четвертых небольшой костыль для молотова в плагине Pop Grenades . Ибо задержка в 1.5 секунды отражается и на начале создания эфекта огня на фитиле.
Код:
#include <amxmodx>
#include <hamsandwich>
#include <reapi>

#define ANIM_NUM         4

new const ITEM_MOLOTOVCLASSNAME[] = "weapon_molotov"; //фикс на молотов, т.к. в планах давать только 1 аммо типу. Зажигание фитиля чтобы без задержки.

enum {
    normal,
    slower,
    medium
};

new const g_GrenadeClassNames[][] = {
    "weapon_flashbang",
    "weapon_hegrenade",
    "weapon_smokegrenade"
};

new const Float:g_VelocityMultiplier[] = {
    1.0,
    0.5,
    0.75
};

new g_HandleThrowType[MAX_CLIENTS + 1];
new Float:g_flLastAttack[MAX_CLIENTS + 1];

public plugin_init() {
    register_plugin("[GRENADE] Pop Grenades", "2.3", "EFFx & HamletEagle & Minni Mouse");

    for(new i; i < sizeof(g_GrenadeClassNames); i++) {
        RegisterHam(Ham_Weapon_SecondaryAttack, g_GrenadeClassNames[i], "Weapon_SecAttack_Pre", .Post = false);
    }

    RegisterHookChain(RG_CBasePlayer_ThrowGrenade, "Player_ThrowGrenade_Pre", .post = false);
}

public Weapon_SecAttack_Pre(pWeapon) {
    if(get_member_game(m_bFreezePeriod)) {
        return HAM_IGNORED;
    }

    if(is_nullent(pWeapon)) {
        return HAM_IGNORED;
    }

    static pPlayer, Float:flCurTime;
    pPlayer = get_member(pWeapon, m_pPlayer);
    flCurTime = get_gametime();

    if(g_flLastAttack[pPlayer] > flCurTime && !FClassnameIs(pWeapon, ITEM_MOLOTOVCLASSNAME)) {
        return HAM_IGNORED;
    }
     
    g_HandleThrowType[pPlayer] = (get_entvar(pPlayer, var_button) & IN_ATTACK) ? medium : slower;
     
    ExecuteHamB(Ham_Weapon_PrimaryAttack, pWeapon);

    g_flLastAttack[pPlayer] = flCurTime + 1.5;

    return HAM_IGNORED;
}

public Player_ThrowGrenade_Pre(pPlayer, grenade, Float:vecSrc[3], Float:vecThrow[3], Float:time, usEvent) {
    if(is_nullent(grenade)) {
        return HC_CONTINUE;
    }

    new Float:flMultiplier = g_VelocityMultiplier[g_HandleThrowType[pPlayer]];

    vecThrow[0] *= flMultiplier;
    vecThrow[1] *= flMultiplier;
    vecThrow[2] *= flMultiplier;

    set_entvar(grenade, var_velocity, vecThrow);

    if(g_HandleThrowType[pPlayer] == slower) {
        rg_send_grenade_anim(pPlayer, ANIM_NUM);
    }

    g_HandleThrowType[pPlayer] = normal;

    return HC_CONTINUE;
}

stock rg_send_grenade_anim(const pPlayer, const iAnimation) {
    set_entvar(pPlayer, var_weaponanim, iAnimation);

    message_begin(MSG_ONE, SVC_WEAPONANIM, .player = pPlayer);
    write_byte(iAnimation);
    write_byte(0);
    message_end();
}

И в завершении скажу.
  • Да Флешку не завезли.
  • Все v_модели имеют анимацию вторичного (слабого) броска.
  • Все w_модели имеют ролл анимации, для установки их в полете.

На этом все. Спасибо за внимание.
 

Вложения

Последнее редактирование:
Сообщения
225
Реакции
90
Помог
1 раз(а)
medusa, ну вот, теперь у меня появилось желание гранаты перепиливать.
 
Сообщения
192
Реакции
148
Помог
1 раз(а)
Дёрнул код (he) из регейма
Код:
#include <amxmodx>
#include <fakemeta>
#include <hamsandwich>
#include <reapi>
#include <xs>

new const ENTITY_GRENADE_MODEL[ ] = "models/w_hegrenade.mdl";

public plugin_init( )
{
    register_clcmd( "test", "tessst" );
    register_clcmd( "test2", "tessst2" );
}

public plugin_precache( )
{
    engfunc( EngFunc_PrecacheModel, ENTITY_GRENADE_MODEL );
}

public tessst( const pPlayer ) CreateGrenade( pPlayer, 1.5 );
public tessst2( const pPlayer )
{
    rg_give_item( pPlayer, "weapon_hegrenade" );
    rg_set_user_bpammo( pPlayer, WEAPON_HEGRENADE, 500 );
}

stock bool: CreateGrenade( const pPlayer, const Float: flTime )
{
    new pEntity = rg_create_entity( "grenade" );

    if ( is_nullent( pEntity ) )
        return false;

    new Float: flGameTime = get_gametime( );
    new Float: vecOrigin[ 3 ]; get_entvar( pPlayer, var_origin, vecOrigin );
    new Float: vecViewOfs[ 3 ]; get_entvar( pPlayer, var_view_ofs, vecViewOfs );

    xs_vec_add( vecOrigin, vecViewOfs, vecOrigin );

    new Float: vecViewAngle[ 3 ]; get_entvar( pPlayer, var_v_angle, vecViewAngle );
    new Float: vecPunchAngle[ 3 ]; get_entvar( pPlayer, var_punchangle, vecPunchAngle );

    xs_vec_add( vecViewAngle, vecPunchAngle, vecViewAngle );

    vecViewAngle[ 0 ] = -10.0 + vecViewAngle[ 0 ] * ( ( ( vecViewAngle[ 0 ] < 0.0 ) ? ( 90.0 - 10.0 ) : ( 90.0 + 10.0 ) ) / 90.0 );

    new Float: vecForward[ 3 ]; angle_vector( vecViewAngle, ANGLEVECTOR_FORWARD, vecForward );

    xs_vec_add_scaled( vecOrigin, vecForward, 16.0, vecOrigin );

    new Float: vecAngles[ 3 ]; get_entvar( pPlayer, var_angles, vecAngles );
    new Float: vecVelocity[ 3 ]; get_entvar( pPlayer, var_velocity, vecVelocity );
    new Float: flSpeed = ( 90.0 - vecViewAngle[ 0 ] ) * 6.0;

    if ( flSpeed > 750.0 )
        flSpeed = 750.0;

    xs_vec_add_scaled( vecVelocity, vecForward, flSpeed, vecVelocity );

    //dllfunc( DLLFunc_Spawn, pEntity );
    ExecuteHam( Ham_Spawn, pEntity );

    set_entvar( pEntity, var_velocity, vecVelocity );
    set_entvar( pEntity, var_angles, vecAngles );
    set_entvar( pEntity, var_gravity, 0.55 );
    set_entvar( pEntity, var_friction, 0.7 );
    set_entvar( pEntity, var_sequence, random_num( 3, 6 ) );
    set_entvar( pEntity, var_framerate, 1.0 );
    set_entvar( pEntity, var_owner, pPlayer );
    set_entvar( pEntity, var_dmgtime, flGameTime + flTime );
    set_entvar( pEntity, var_nextthink, flGameTime + 0.1 );

    //UTIL_SetEntityAnim( pEntity, random_num( 3, 6 ) );

    set_member( pEntity, m_Grenade_bJustBlew, true );

    engfunc( EngFunc_SetModel, pEntity, ENTITY_GRENADE_MODEL );
    engfunc( EngFunc_SetOrigin, pEntity, vecOrigin );

    SetTouch( pEntity, "CGrenade__Touch" );
    SetThink( pEntity, "CGrenade__Think" );

    return true;
}

public CGrenade__Think( const pEntity )
{
    if ( is_nullent( pEntity ) )
        return;

    if ( !ExecuteHam( Ham_IsInWorld, pEntity ) )
    {
        SetTouch( pEntity, "" );
        SetThink( pEntity, "" );
        UTIL_KillEntity( pEntity );
        return;
    }

    static Float: flGameTime; flGameTime = get_gametime( );

    StudioFrameAdvance( pEntity );
    set_entvar( pEntity, var_nextthink, flGameTime + 0.1 );

    if ( get_entvar( pEntity, var_dmgtime ) <= flGameTime )
    {
        client_print( 0, print_center, "BOOOOOM" );
        SetTouch( pEntity, "" );
        SetThink( pEntity, "" );
        UTIL_KillEntity( pEntity );
        return;
    }

    if ( get_entvar( pEntity, var_waterlevel ) != 0 )
    {
        static Float: vecVelocity[ 3 ]; get_entvar( pEntity, var_velocity, vecVelocity );
        xs_vec_mul_scalar( vecVelocity, 0.5, vecVelocity );
        set_pev( pEntity, pev_velocity, vecVelocity );
        set_entvar( pEntity, var_framerate, 0.2 );
    }
}

public CGrenade__Touch( const pEntity, const pToucher )
{
    if ( is_nullent( pEntity ) )
        return;

    if ( pToucher == get_entvar( pEntity, var_owner ) )
        return;

    static Float: vecVelocity[ 3 ]; get_entvar( pEntity, var_velocity, vecVelocity );

    if ( FClassnameIs( pToucher, "info_target" ) && get_entvar( pToucher, var_rendermode ) != kRenderNormal )
    {
        xs_vec_mul_scalar( vecVelocity, -2.0, vecVelocity );
        set_pev( pEntity, pev_velocity, vecVelocity );
    }

    static iBounceCount; iBounceCount = get_member( pEntity, m_Grenade_iBounceCount );

    if ( get_entvar( pEntity, var_flags ) & FL_ONGROUND )
    {
        xs_vec_mul_scalar( vecVelocity, 0.8, vecVelocity );
        set_pev( pEntity, pev_velocity, vecVelocity );
        set_pev( pEntity, pev_sequence, 1 ); // pev->sequence = RANDOM_LONG(1, 1); // TODO: what?
    }
    else
    {
        if ( iBounceCount < 5 )
        {
            client_print( 0, print_chat, "Sound" );
            rh_emit_sound2( pEntity, 0, CHAN_VOICE, fmt( "weapons/grenade_hit%i.wav", random_num( 1, 3 ) ), 0.25 );
        }

        if ( iBounceCount >= 10 )
        {
            set_entvar( pEntity, var_groundentity, 0 );
            set_entvar( pEntity, var_flags, get_entvar( pEntity, var_flags ) | FL_ONGROUND );
            set_entvar( pEntity, var_velocity, NULL_VECTOR );
        }

        set_member( pEntity, m_Grenade_iBounceCount, iBounceCount + 1 );
    }

    static Float: flFrameRate; flFrameRate = xs_vec_len( vecVelocity ) / 200.0;

    client_print( 0, print_chat, "flFrameRate %f", flFrameRate );

    if ( flFrameRate > 1.0 ) flFrameRate = 1.0
    else if ( flFrameRate < 0.5 ) flFrameRate = 0.0;

    set_entvar( pEntity, var_framerate, flFrameRate );
}

stock Float: StudioFrameAdvance( const pEntity, Float: flInterval = 0.0 )
{
    new Float: flGameTime = get_gametime( );
    new Float: flAnimTime = get_entvar( pEntity, var_animtime );

    if ( flInterval == 0.0 )
    {
        flInterval = flGameTime - flAnimTime;

        if ( flInterval <= 0.001 )
        {
            set_entvar( pEntity, var_animtime, flGameTime );
            return 0.0;
        }
    }

    if ( flAnimTime == 0.0 )
        flInterval = 0.0;

    new Float: flFrame = get_entvar( pEntity, var_frame );

    flFrame += flInterval * get_member( pEntity, m_flFrameRate ) * get_entvar( pEntity, var_framerate );
    set_entvar( pEntity, var_animtime, flGameTime );

    if ( flFrame < 0.0 || flFrame >= 256.0 )
    {
        flFrame -= ( get_member( pEntity, m_fSequenceLoops ) ) ? ( ( flFrame / 256.0 ) * 256.0 ) : ( ( flFrame < 0.0 ) ? 0.0 : 255.0 );
        set_member( pEntity, m_fSequenceFinished, true );
    }

    set_entvar( pEntity, var_frame, flFrame );

    return flInterval;
}

stock UTIL_SetEntityAnim( const pEntity, const iSequence )
{
    set_pev( pEntity, pev_frame, 1.0 );
    set_pev( pEntity, pev_framerate, 1.0 );
    set_pev( pEntity, pev_animtime, get_gametime( ) );
    set_pev( pEntity, pev_sequence, iSequence );
}

stock UTIL_KillEntity( const pEntity )
{
    set_entvar( pEntity, var_flags, FL_KILLME );
    set_entvar( pEntity, var_nextthink, get_gametime( ) );
}
 
Последнее редактирование:
Сообщения
133
Реакции
441
Помог
2 раз(а)
Скрытое содержимое для пользователей: Ruby
 
Сообщения
775
Реакции
291
Помог
11 раз(а)
А теперь к тому что криво, косо, по хайденсиxxxке
Ну судя по видео, граната взрывается только на горизонтальных поверхностях. Хотя по логике веще она взрываться должна, с соприкасанием с любой поверхностью, кроме живого игрока
 
Сообщения
133
Реакции
441
Помог
2 раз(а)
Заменил архив в первом посте. Забыл поменять спрайт и тхт от худа.
 

Вложения

  • 5.5 KB Просмотры: 48
Сообщения
3,328
Реакции
1,462
Помог
124 раз(а)
medusa, а, вот в чем дело. А то я установил потестить, заметил проблемы с худом, но в коде не стал копаться. Хотел было сообщить, но вспомнил про:
Критику, споры, предложения и так далее в мой адрес можете не высказывать
 
Сообщения
694
Реакции
472
Помог
10 раз(а)
Скрытое содержимое для пользователей: medusa
 
Сообщения
133
Реакции
441
Помог
2 раз(а)
Скрытое содержимое для пользователей: BalbuR
 
Сообщения
37
Реакции
-3
very good, thanks for posting. I gave some adjustments

corrected sounds
damage working
fitted model
corrected hud
and some things in the code

 
Сообщения
11
Реакции
-1
Помог
1 раз(а)
Народ всем добрый, значит поставил молотов медузы, по команде Say 1, тест работает, а вот купить через say buy_molotov нечего не происходит, кто знает где косяк, прошу помощи. Спасибо заранее
 
Сообщения
130
Реакции
7
I can't compile this plugin...and I have no errors, it just doesn't compile
 
Сообщения
11
Реакции
-1
Помог
1 раз(а)
Schokk, И да, даже если я скину молотов под ногами, ХП остаються.
 
Сообщения
3,328
Реакции
1,462
Помог
124 раз(а)
BlasteeM, а что ты хотел? По-моему, автор ясно дал понять, что это наработка, а не готовый ресурс.
 
Сообщения
2,827
Реакции
1,662
Помог
75 раз(а)
Huehue, во-вторых это наработка, статья, а не готовый ресурс, плагин.
 
Сообщения
4
Реакции
-5
Не аргументированная критика
medusa, неработает твой плагин в паре с плагином лечебной гранаты от радиуса, и нет никакого 5-ого пункта меню гранат.
уставливал из ПУ хоста кссерв....толи он залит хреново на хост толи сам плагин кривой.
 
Сообщения
37
Реакции
0
Помог
1 раз(а)
По какому принципу muzzleflash цепляется к фитилю?
На другую модель никак не прицепить его?
 
Сообщения
1,487
Реакции
1,480
Помог
2 раз(а)
Естественно вся реализация была успешна украдена у СИСЫ, а по другому и не могло быть.
Не,ничего ты не крал
Он же сам взял с ксго это всё

То,что он первый сделал в 1.6 - да это так
И ты лишь последовал дальше

Другое дело,если бы вся эта идея принадлежала только ему и она нигде вообще не была замечена,а тут ты сделал - то я согласен
 
  • Нравится
Реакции: Loki

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

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