Помощь Преодоление препятствий у NPC зомби КС 1.6

Robert7791

Новичок
Участник
12.06.2023
5
0
Добрый день!
Код:
#include <amxmodx>
#include <amxmisc>
#include <engine>
#include <hamsandwich>
#include <fakemeta>
#include <fakemeta_util>
#include <xs>
#include <zombie_plague_special>

native zl_player_alive();                                            // Проверка на количество живых игроков [boss_basic.sma]
native zl_player_random();                                            // Получение живого случайного игрока [boss_basic.sma]
native zl_boss_map();                                                // Проверка на карты Боссов [boss_basic.sma]
native zl_boss_valid(id);                                            // Проверка валидности Босса [boss_basic.sma]

const zombie_blood = 83;                                            // Цвет крови Зомби
const zombie_limit = 35;                                            // Лимит NPC Зомби
const Float:time_attack = 0.5;                                        // Время атаки при соприкосновении с игроком
const Float:time_delete = 1.5;                                        // Время на удаление NPC

new const ZmClassicMdl[] = "models/player/npc_zombies/classic/classic.mdl";
new const ZmDeimosMdl[] = "models/player/npc_zombies/deimos/deimos.mdl";
new const ZmGhostMdl[] = "models/player/npc_zombies/ghost/ghost.mdl";
new const ZmHealMdl[] = "models/player/npc_zombies/heal/heal.mdl";
new const ZmWitchMdl[] = "models/player/npc_zombies/witch/witch.mdl";
new const ZmBigMdl[] = "models/player/npc_zombies/big/big.mdl";
new const ZmHoundMdl[] = "models/player/npc_zombies/hound/hound.mdl";
new const GrenadeMdl[] = "models/citydarkru/weapons/w_models8.mdl"

new const SoundClassic[][] = { "citydarkru/zombies/allfunc/classic_dead_1.wav", "citydarkru/zombies/allfunc/hitnormal_personage.wav", "citydarkru/zombies/allfunc/classic_idle_1.wav" };
new const SoundDeimos[][] = { "citydarkru/zombies/allfunc/deimos_dead_1.wav", "citydarkru/zombies/allfunc/hitnormal_personage.wav", "citydarkru/zombies/allfunc/deimos_idle_1.wav" };
new const SoundGhost[][] = { "citydarkru/zombies/allfunc/ghost_dead_1.wav", "citydarkru/zombies/allfunc/hitnormal_personage.wav", "citydarkru/zombies/allfunc/ghost_idle_1.wav" };
new const SoundHeal[][] = { "citydarkru/zombies/allfunc/healer_dead_1.wav", "citydarkru/zombies/allfunc/hitnormal_personage.wav", "citydarkru/zombies/allfunc/healer_idle_1.wav" };
new const SoundWitch[][] = { "citydarkru/zombies/allfunc/witch_dead_1.wav", "citydarkru/zombies/allfunc/hitnormal_personage.wav", "citydarkru/zombies/allfunc/witch_idle_1.wav" };
new const SoundBig[][] = { "citydarkru/zombies/allfunc/big_dead_2.wav", "citydarkru/zombies/allfunc/hitnormal_personage.wav", "citydarkru/zombies/allfunc/big_idle_2.wav" };
new const SoundHound[][] = { "citydarkru/zombies/allfunc/hound_dead_1.wav", "citydarkru/zombies/allfunc/hitnormal_personage.wav", "citydarkru/zombies/allfunc/hound_idle_1.wav" };

static Float:Speed;
static bool:TakeDamageFromZM;
static ZombieNpc[zombie_limit];
static ZombieNum, ZombieCount, Damage;
static Float:DamageHitPlayer[33];
static CountForNewTarget;
static iTarget;
static Healer_Sprite, Deimos_Sprite_Line, Deimos_Sprite_Exp, Grenade_Sprite_Exp;

const WPN_NOT_DROP = ((1<<2)|(1<<CSW_HEGRENADE)|(1<<CSW_SMOKEGRENADE)|(1<<CSW_FLASHBANG)|(1<<CSW_KNIFE)|(1<<CSW_C4));

public plugin_init()
{
    register_plugin("[CFN-SERVER] Boss ZombieSystem", "1.9", "Alexander.3/[cfn]");
    
    // Останавливаем плагин, если не идет битва с Боссом или идет битва с Джаггернаутом
    //if(!zl_boss_map() || zl_boss_map() == 14) {
    //    pause("ad");
    //    return;
    //}
    
    //if(!zl_boss_map()) {
    //    pause("ad");
    //    return;
    //}


    RegisterHam(Ham_BloodColor, "monster_hevsuit_dead", "Hook_BloodColor");
    RegisterHam(Ham_Think, "monster_hevsuit_dead", "Hook_Think");
    RegisterHam(Ham_Touch, "monster_hevsuit_dead", "Hook_Touch");
    RegisterHam(Ham_Killed, "monster_hevsuit_dead", "Hook_Killed");
    
    register_touch("grenade_skill", "*", "fw_Weapon_Touch");
    
    register_forward(FM_Touch, "fw_Touch");
    register_cvar("plus_coord", "200.0")
    
    TakeDamageFromZM = true;
    CountForNewTarget = 0;
}

public plugin_precache()
{
    // Убираем прекеш, если не идет битва с Боссом или идет битва с Джаггернаутом
    //if(!zl_boss_map())
        //return;
        
    precache_model(ZmClassicMdl);
    precache_model(ZmDeimosMdl);
    precache_model(ZmGhostMdl);
    precache_model(ZmHealMdl);
    precache_model(ZmWitchMdl);
    precache_model(ZmBigMdl);
    precache_model(ZmHoundMdl);
    precache_model(GrenadeMdl);
    
    Healer_Sprite = precache_model("sprites/citydarkru/zombies/abilityfunc/restore_health.spr");
    Deimos_Sprite_Line = precache_model("sprites/laserbeam.spr");
    Deimos_Sprite_Exp = precache_model("sprites/citydarkru/zombies/abilityfunc/deimos_exp.spr");
    Grenade_Sprite_Exp = precache_model("sprites/citydarkru/zombies/abilityfunc/deimos_exp.spr");
    
    for(new i; i < sizeof SoundClassic; ++i)
        precache_sound(SoundClassic[i]);
    
    for(new i; i < sizeof SoundDeimos; ++i)
        precache_sound(SoundDeimos[i]);
    
    for(new i; i < sizeof SoundGhost; ++i)
        precache_sound(SoundGhost[i]);
    
    for(new i; i < sizeof SoundHeal; ++i)
        precache_sound(SoundHeal[i]);
    
    for(new i; i < sizeof SoundWitch; ++i)
        precache_sound(SoundWitch[i]);
    
    for(new i; i < sizeof SoundBig; ++i)
        precache_sound(SoundBig[i]);
    
    for(new i; i < sizeof SoundHound; ++i)
        precache_sound(SoundHound[i]);
    
    precache_sound("citydarkru/zombies/abilityfunc/td_heal.wav");
    precache_sound("citydarkru/zombies/abilityfunc/deimos_start.wav");
    precache_sound("citydarkru/zombies/abilityfunc/deimos_hit.wav");
    precache_sound("citydarkru/zombies/abilityfunc/invisable_active.wav");
    precache_sound("weapons/zombie_bomb_exp.wav");
}

public plugin_natives()
{
    register_native("zl_zmclassic_valid", "native_zl_zmclassic_valid", 1);
    register_native("zl_zmdeimos_valid", "native_zl_zmdeimos_valid", 1);
    register_native("zl_zmghost_valid", "native_zl_zmghost_valid", 1);
    register_native("zl_zmheal_valid", "native_zl_zmheal_valid", 1);
    register_native("zl_zmwitch_valid", "native_zl_zmwitch_valid", 1);
    register_native("zl_zmbig_valid", "native_zl_zmbig_valid", 1);
    register_native("zl_zmhound_valid", "native_zl_zmhound_valid", 1);
    
    register_native("zl_zombie_count", "native_zl_zombie_count", 1);
    register_native("zl_zombie_create", "native_zl_zombie_create", 1);
    register_native("zl_zombie_delete", "native_zl_zombie_delete", 1);
}

public native_zl_zombie_delete()
{
    for(new i = 0; i < entity_count(); i++)
    {
        if(native_zl_zmclassic_valid(i) || native_zl_zmdeimos_valid(i) || native_zl_zmghost_valid(i) || native_zl_zmheal_valid(i) || native_zl_zmwitch_valid(i) || native_zl_zmbig_valid(i) || native_zl_zmhound_valid(i))
        {
            if(pev(i, pev_deadflag) != DEAD_DYING)
            {
                set_pev(i, pev_velocity, {0.0, 0.0, 0.0});
                set_pev(i, pev_solid, SOLID_NOT);
                set_pev(i, pev_deadflag, DEAD_DYING);
                
                static ClassName[63];
                pev(i, pev_classname, ClassName, charsmax(ClassName));
                
                if(contain(ClassName, "NpcHound_" ) != -1)
                    Anim(i, random_num(14, 15), 1.1);
                else
                    Anim(i, random_num(101, 102), 1.1);
                
                set_task(time_delete, "Zombie_Delete", i);
                
                if(contain(ClassName, "NpcClassic_" ) != -1) engfunc(EngFunc_EmitSound, i, CHAN_VOICE, SoundClassic[0], VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
                
                if(contain(ClassName, "NpcDeimos_" ) != -1) engfunc(EngFunc_EmitSound, i, CHAN_VOICE, SoundDeimos[0], VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
                
                if(contain(ClassName, "NpcGhost_" ) != -1) engfunc(EngFunc_EmitSound, i, CHAN_VOICE, SoundGhost[0], VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
                
                if(contain(ClassName, "NpcHeal_" ) != -1) engfunc(EngFunc_EmitSound, i, CHAN_VOICE, SoundHeal[0], VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
                
                if(contain(ClassName, "NpcWitch_" ) != -1) engfunc(EngFunc_EmitSound, i, CHAN_VOICE, SoundWitch[0], VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
                
                if(contain(ClassName, "NpcBig_" ) != -1) engfunc(EngFunc_EmitSound, i, CHAN_VOICE, SoundBig[0], VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
                
                if(contain(ClassName, "NpcHound_" ) != -1) engfunc(EngFunc_EmitSound, i, CHAN_VOICE, SoundHound[0], VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
            }
        }
    }
    
    TakeDamageFromZM = false;
}

public native_zl_zombie_create(Float:Origin[3], Health, speed, damage)
{
    if(ZombieCount >= zombie_limit)
        return;
        
    for(new i; i < zombie_limit; ++i)
    {
        if(pev_valid(ZombieNpc[i]))
            continue;
    
        ZombieNum = i;
    }
    
    param_convert(1);
    
    ZombieNpc[ZombieNum] = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "monster_hevsuit_dead"));
    
    switch(random_num(1, 7))
    {
        case 1:
        {
            engfunc(EngFunc_SetModel, ZombieNpc[ZombieNum], ZmClassicMdl);
            engfunc(EngFunc_SetSize, ZombieNpc[ZombieNum], Float:{-15.0, -15.0, -36.0}, Float:{15.0, 15.0, 96.0});
            engfunc(EngFunc_SetOrigin, ZombieNpc[ZombieNum], Origin);
            
            new ClassName[32];
            formatex(ClassName, charsmax(ClassName), "NpcClassic_%d", ZombieCount);
            
            set_pev(ZombieNpc[ZombieNum], pev_classname, ClassName);
            set_pev(ZombieNpc[ZombieNum], pev_solid, SOLID_BBOX);
            set_pev(ZombieNpc[ZombieNum], pev_movetype, MOVETYPE_PUSHSTEP);
            set_pev(ZombieNpc[ZombieNum], pev_takedamage, DAMAGE_YES);
            set_pev(ZombieNpc[ZombieNum], pev_health, (float(Health) * 0.25));
            set_pev(ZombieNpc[ZombieNum], pev_deadflag, DEAD_NO);
            set_pev(ZombieNpc[ZombieNum], pev_nextthink, get_gametime() + 0.1);
            set_pev(ZombieNpc[ZombieNum], pev_body, random_num(0, 2));
            
            drop_to_floor(ZombieNpc[ZombieNum]);
            Anim(ZombieNpc[ZombieNum], 4, 1.0);
            
            engfunc(EngFunc_EmitSound, ZombieNpc[ZombieNum], CHAN_VOICE, SoundClassic[2], VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
            
            new ability_grenade_classic = random_num(1, 3);
            
            if(ability_grenade_classic == 1 && zl_player_alive() > 0)
                set_task(5.0, "SkillGrenade", 505+ZombieNpc[ZombieNum]);
        }
        case 2:
        {
            engfunc(EngFunc_SetModel, ZombieNpc[ZombieNum], ZmDeimosMdl);
            engfunc(EngFunc_SetSize, ZombieNpc[ZombieNum], Float:{-15.0, -15.0, -36.0}, Float:{15.0, 15.0, 96.0});
            engfunc(EngFunc_SetOrigin, ZombieNpc[ZombieNum], Origin);
            
            new ClassName[32];
            formatex(ClassName, charsmax(ClassName), "NpcDeimos_%d", ZombieCount);
            
            set_pev(ZombieNpc[ZombieNum], pev_classname, ClassName);
            set_pev(ZombieNpc[ZombieNum], pev_solid, SOLID_BBOX);
            set_pev(ZombieNpc[ZombieNum], pev_movetype, MOVETYPE_PUSHSTEP);
            set_pev(ZombieNpc[ZombieNum], pev_takedamage, DAMAGE_YES);
            set_pev(ZombieNpc[ZombieNum], pev_health, (float(Health) * 1));
            set_pev(ZombieNpc[ZombieNum], pev_deadflag, DEAD_NO);
            set_pev(ZombieNpc[ZombieNum], pev_nextthink, get_gametime() + 0.1);
            set_pev(ZombieNpc[ZombieNum], pev_body, random_num(0, 1));
            
            drop_to_floor(ZombieNpc[ZombieNum]);
            Anim(ZombieNpc[ZombieNum], 4, 1.0);
            
            engfunc(EngFunc_EmitSound, ZombieNpc[ZombieNum], CHAN_VOICE, SoundDeimos[2], VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
            
            new ability_deimos = random_num(1, 3);
            
            if(ability_deimos == 1 && zl_player_alive() > 0)
                set_task(3.0, "SkillDeimos", 202+ZombieNpc[ZombieNum]);
        }
        case 3:
        {
            engfunc(EngFunc_SetModel, ZombieNpc[ZombieNum], ZmGhostMdl);
            engfunc(EngFunc_SetSize, ZombieNpc[ZombieNum], Float:{-15.0, -15.0, -36.0}, Float:{15.0, 15.0, 96.0});
            engfunc(EngFunc_SetOrigin, ZombieNpc[ZombieNum], Origin);
            
            new ClassName[32];
            formatex(ClassName, charsmax(ClassName), "NpcGhost_%d", ZombieCount);
            
            set_pev(ZombieNpc[ZombieNum], pev_classname, ClassName);
            set_pev(ZombieNpc[ZombieNum], pev_solid, SOLID_BBOX);
            set_pev(ZombieNpc[ZombieNum], pev_movetype, MOVETYPE_PUSHSTEP);
            set_pev(ZombieNpc[ZombieNum], pev_takedamage, DAMAGE_YES);
            set_pev(ZombieNpc[ZombieNum], pev_health, (float(Health) * 0.5));
            set_pev(ZombieNpc[ZombieNum], pev_deadflag, DEAD_NO);
            set_pev(ZombieNpc[ZombieNum], pev_nextthink, get_gametime() + 0.1);
            set_pev(ZombieNpc[ZombieNum], pev_body, random_num(0, 1));
            
            drop_to_floor(ZombieNpc[ZombieNum]);
            Anim(ZombieNpc[ZombieNum], 4, 1.0);
            
            engfunc(EngFunc_EmitSound, ZombieNpc[ZombieNum], CHAN_VOICE, SoundGhost[2], VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
            
            new ability_ghost = random_num(1, 3);
            
            if(ability_ghost == 1 && zl_player_alive() > 0)
                set_task(3.0, "SkillGhost", 303+ZombieNpc[ZombieNum]);
        }
        case 4:
        {
            engfunc(EngFunc_SetModel, ZombieNpc[ZombieNum], ZmHealMdl);
            engfunc(EngFunc_SetSize, ZombieNpc[ZombieNum], Float:{-15.0, -15.0, -36.0}, Float:{15.0, 15.0, 96.0});
            engfunc(EngFunc_SetOrigin, ZombieNpc[ZombieNum], Origin);
            
            new ClassName[32];
            formatex(ClassName, charsmax(ClassName), "NpcHeal_%d", ZombieCount);
            
            set_pev(ZombieNpc[ZombieNum], pev_classname, ClassName);
            set_pev(ZombieNpc[ZombieNum], pev_solid, SOLID_BBOX);
            set_pev(ZombieNpc[ZombieNum], pev_movetype, MOVETYPE_PUSHSTEP);
            set_pev(ZombieNpc[ZombieNum], pev_takedamage, DAMAGE_YES);
            set_pev(ZombieNpc[ZombieNum], pev_health, (float(Health) * 0.5));
            set_pev(ZombieNpc[ZombieNum], pev_deadflag, DEAD_NO);
            set_pev(ZombieNpc[ZombieNum], pev_nextthink, get_gametime() + 0.1);
            set_pev(ZombieNpc[ZombieNum], pev_body, random_num(0, 1));
            
            drop_to_floor(ZombieNpc[ZombieNum]);
            Anim(ZombieNpc[ZombieNum], 4, 1.0);
            
            engfunc(EngFunc_EmitSound, ZombieNpc[ZombieNum], CHAN_VOICE, SoundHeal[2], VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
            
            new ability_heal = random_num(1, 3);
            
            if(ability_heal == 1 && zl_player_alive() > 0)
                set_task(3.0, "SkillHeal", 101+ZombieNpc[ZombieNum]);
        }
        case 5:
        {
            engfunc(EngFunc_SetModel, ZombieNpc[ZombieNum], ZmWitchMdl);
            engfunc(EngFunc_SetSize, ZombieNpc[ZombieNum], Float:{-15.0, -15.0, -36.0}, Float:{15.0, 15.0, 96.0});
            engfunc(EngFunc_SetOrigin, ZombieNpc[ZombieNum], Origin);
            
            new ClassName[32];
            formatex(ClassName, charsmax(ClassName), "NpcWitch_%d", ZombieCount);
            
            set_pev(ZombieNpc[ZombieNum], pev_classname, ClassName);
            set_pev(ZombieNpc[ZombieNum], pev_solid, SOLID_BBOX);
            set_pev(ZombieNpc[ZombieNum], pev_movetype, MOVETYPE_PUSHSTEP);
            set_pev(ZombieNpc[ZombieNum], pev_takedamage, DAMAGE_YES);
            set_pev(ZombieNpc[ZombieNum], pev_health, (float(Health) * 0.5));
            set_pev(ZombieNpc[ZombieNum], pev_deadflag, DEAD_NO);
            set_pev(ZombieNpc[ZombieNum], pev_nextthink, get_gametime() + 0.1);
            set_pev(ZombieNpc[ZombieNum], pev_body, random_num(0, 1));
            
            drop_to_floor(ZombieNpc[ZombieNum]);
            Anim(ZombieNpc[ZombieNum], 4, 1.0);
            
            engfunc(EngFunc_EmitSound, ZombieNpc[ZombieNum], CHAN_VOICE, SoundWitch[2], VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
            
            new ability_grenade_witch = random_num(1, 3);
            
            if(ability_grenade_witch == 1 && zl_player_alive() > 0)
                set_task(5.0, "SkillGrenade", 505+ZombieNpc[ZombieNum]);
        }
        case 6:
        {
            engfunc(EngFunc_SetModel, ZombieNpc[ZombieNum], ZmBigMdl);
            engfunc(EngFunc_SetSize, ZombieNpc[ZombieNum], Float:{-15.0, -15.0, -36.0}, Float:{15.0, 15.0, 96.0});
            engfunc(EngFunc_SetOrigin, ZombieNpc[ZombieNum], Origin);
            
            new ClassName[32];
            formatex(ClassName, charsmax(ClassName), "NpcBig_%d", ZombieCount);
            
            set_pev(ZombieNpc[ZombieNum], pev_classname, ClassName);
            set_pev(ZombieNpc[ZombieNum], pev_solid, SOLID_BBOX);
            set_pev(ZombieNpc[ZombieNum], pev_movetype, MOVETYPE_PUSHSTEP);
            set_pev(ZombieNpc[ZombieNum], pev_takedamage, DAMAGE_YES);
            set_pev(ZombieNpc[ZombieNum], pev_health, (float(Health) * 2));
            set_pev(ZombieNpc[ZombieNum], pev_deadflag, DEAD_NO);
            set_pev(ZombieNpc[ZombieNum], pev_nextthink, get_gametime() + 0.1);
            set_pev(ZombieNpc[ZombieNum], pev_body, random_num(0, 1));
            
            drop_to_floor(ZombieNpc[ZombieNum]);
            Anim(ZombieNpc[ZombieNum], 4, 1.0);
            
            engfunc(EngFunc_EmitSound, ZombieNpc[ZombieNum], CHAN_VOICE, SoundBig[2], VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
            
            new ability_grenade_big = random_num(1, 3);
            
            if(ability_grenade_big == 1 && zl_player_alive() > 0)
                set_task(5.0, "SkillGrenade", 505+ZombieNpc[ZombieNum]);
        }
        case 7:
        {
            engfunc(EngFunc_SetModel, ZombieNpc[ZombieNum], ZmHoundMdl);
            engfunc(EngFunc_SetSize, ZombieNpc[ZombieNum], Float:{-5.1, -5.1, -5.1}, Float:{5.1, 5.1, 15.1});
            engfunc(EngFunc_SetOrigin, ZombieNpc[ZombieNum], Origin);
            
            new ClassName[32];
            formatex(ClassName, charsmax(ClassName), "NpcHound_%d", ZombieCount);
            
            set_pev(ZombieNpc[ZombieNum], pev_classname, ClassName);
            set_pev(ZombieNpc[ZombieNum], pev_solid, SOLID_BBOX);
            set_pev(ZombieNpc[ZombieNum], pev_movetype, MOVETYPE_PUSHSTEP);
            set_pev(ZombieNpc[ZombieNum], pev_takedamage, DAMAGE_YES);
            set_pev(ZombieNpc[ZombieNum], pev_health, (float(Health) * 1));
            set_pev(ZombieNpc[ZombieNum], pev_deadflag, DEAD_NO);
            set_pev(ZombieNpc[ZombieNum], pev_nextthink, get_gametime() + 0.1);
            set_pev(ZombieNpc[ZombieNum], pev_body, 0);
            
            drop_to_floor(ZombieNpc[ZombieNum]);
            Anim(ZombieNpc[ZombieNum], 4, 1.0);
            
            engfunc(EngFunc_EmitSound, ZombieNpc[ZombieNum], CHAN_VOICE, SoundHound[2], VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
        }
    }
    
    Speed = float(speed);
    Damage = damage;
    
    ZombieCount++;
    CountForNewTarget++;
}

public Hook_Think(Ent)
{
    if(!pev_valid(Ent))
        return HAM_IGNORED;
        
    if(!native_zl_zmclassic_valid(Ent) && !native_zl_zmdeimos_valid(Ent) && !native_zl_zmghost_valid(Ent) && !native_zl_zmheal_valid(Ent) && !native_zl_zmwitch_valid(Ent) && !native_zl_zmbig_valid(Ent) && !native_zl_zmhound_valid(Ent))
        return HAM_IGNORED;
        
    if(pev(Ent, pev_deadflag) == DEAD_DYING)
        return HAM_IGNORED;
    
    if(!is_user_alive(iTarget))
    {
        iTarget = zl_player_random();
        
        set_pev(Ent, pev_nextthink, get_gametime() + 0.2);
        
        return HAM_HANDLED;
    }
    
    if(pev(Ent, pev_fuser1) == 500.0)
    {
        set_pev(Ent, pev_fuser1, 0.0);
        
        Anim(Ent, 4, 1.0);
    }
    
    static Float:Origin[3], Float:eOrigin[3], Float:Angle[3], Float:Vector[3];
    
    pev(iTarget, pev_origin, Origin);
    pev(Ent, pev_origin, eOrigin);

    xs_vec_sub(Origin, eOrigin, Vector);
    vector_to_angle(Vector, Angle);
    
    Angle[0] = 0.0;
    Angle[2] = 0.0;

    xs_vec_normalize(Vector, Vector);
    xs_vec_mul_scalar(Vector, Speed, Vector);
    
    if(Vector[2] > 0.0)
    {
        Vector[2] = 0.0
    }
    else
        Vector[2] -= 500.0;

    set_pev(Ent, pev_velocity, Vector);
    set_pev(Ent, pev_angles, Angle);

    set_pev(Ent, pev_nextthink, get_gametime() + 0.2);
    
    return HAM_HANDLED;
}

public Hook_Killed(victim, attacker, corpse)
{
    if(!native_zl_zmclassic_valid(victim) && !native_zl_zmdeimos_valid(victim) && !native_zl_zmghost_valid(victim) && !native_zl_zmheal_valid(victim) && !native_zl_zmwitch_valid(victim) && !native_zl_zmbig_valid(victim) && !native_zl_zmhound_valid(victim))
        return HAM_IGNORED;
    
    if(pev(victim, pev_deadflag) == DEAD_DYING)
        return HAM_IGNORED;
    
    set_pev(victim, pev_velocity, {0.0, 0.0, 0.0});
    set_pev(victim, pev_solid, SOLID_NOT);
    set_pev(victim, pev_deadflag, DEAD_DYING);
    
    static ClassName[63];
    pev(victim, pev_classname, ClassName, charsmax(ClassName));
    
    if(contain(ClassName, "NpcHound_" ) != -1)
        Anim(victim, random_num(14, 15), 1.1);
    else
        Anim(victim, random_num(101, 102), 1.1);
    
    set_task(time_delete, "Zombie_Delete", victim);
    
    if(contain(ClassName, "NpcClassic_" ) != -1) engfunc(EngFunc_EmitSound, victim, CHAN_VOICE, SoundClassic[0], VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
    
    if(contain(ClassName, "NpcDeimos_" ) != -1) engfunc(EngFunc_EmitSound, victim, CHAN_VOICE, SoundDeimos[0], VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
    
    if(contain(ClassName, "NpcGhost_" ) != -1) engfunc(EngFunc_EmitSound, victim, CHAN_VOICE, SoundGhost[0], VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
    
    if(contain(ClassName, "NpcHeal_" ) != -1) engfunc(EngFunc_EmitSound, victim, CHAN_VOICE, SoundHeal[0], VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
    
    if(contain(ClassName, "NpcWitch_" ) != -1) engfunc(EngFunc_EmitSound, victim, CHAN_VOICE, SoundWitch[0], VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
    
    if(contain(ClassName, "NpcBig_" ) != -1) engfunc(EngFunc_EmitSound, victim, CHAN_VOICE, SoundBig[0], VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
    
    if(contain(ClassName, "NpcHound_" ) != -1) engfunc(EngFunc_EmitSound, victim, CHAN_VOICE, SoundHound[0], VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
    
    zp_set_user_ammo_packs(attacker, zp_get_user_ammo_packs(attacker) + 100);
    
    CountForNewTarget--;
    
    if(CountForNewTarget == 0)
        iTarget = zl_player_random();
    
    if(task_exists(victim+101))
        remove_task(victim+101);
    
    if(task_exists(victim+202))
        remove_task(victim+202);
    
    if(task_exists(victim+303))
        remove_task(victim+303);
    
    if(task_exists(victim+404))
        remove_task(victim+404);
    
    if(task_exists(victim+505))
        remove_task(victim+505);
    
    if(task_exists(victim+606))
        remove_task(victim+606);
    
    return HAM_SUPERCEDE;
}

public Zombie_Delete(id)
{
    engfunc(EngFunc_RemoveEntity, id);
    
    ZombieCount--;
}

public Hook_Touch(Ent, id)
{
    if((!native_zl_zmclassic_valid(Ent) && !native_zl_zmdeimos_valid(Ent) && !native_zl_zmghost_valid(Ent) && !native_zl_zmheal_valid(Ent) && !native_zl_zmwitch_valid(Ent) && !native_zl_zmbig_valid(Ent) && !native_zl_zmhound_valid(Ent)) || !is_user_alive(id))
        return HAM_IGNORED;
        
    if(pev(Ent, pev_deadflag) == DEAD_DYING)
        return HAM_IGNORED;
    
    if(TakeDamageFromZM == false)
        return HAM_IGNORED;
    
    if(DamageHitPlayer[id] <= get_gametime())
    {
        zm_damage(id, Damage);
        
        DamageHitPlayer[id] = get_gametime() + 0.5;
    }
    
    set_pev(Ent, pev_nextthink, get_gametime() + time_attack);
    set_pev(Ent, pev_fuser1, 500.0);
    
    Anim(Ent, 76, 1.0);
    
    engfunc(EngFunc_EmitSound, Ent, CHAN_VOICE, SoundClassic[1], VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
    
    return HAM_HANDLED;
}

public SkillHeal(id)
{
    id -= 101;
    
    if(pev_valid(id) && pev(id, pev_deadflag) != DEAD_DYING)
    {
        new Float:Origin[3];
        pev(id, pev_origin, Origin);
        
        Origin[2] -= 35.0;
        
        Heal_Effect(Origin);
        
        set_pev(id, pev_health, 500.0);
        
        engfunc(EngFunc_EmitSound, id, CHAN_VOICE, "citydarkru/zombies/abilityfunc/td_heal.wav", VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
    }
}

public SkillDeimos(id)
{
    id -= 202;
    
    if(pev_valid(id) && (pev(id, pev_deadflag) != DEAD_DYING) && zl_player_alive() > 0)
    {
        Anim(id, 10, 2.0);
        
        set_task(0.5, "SkillUpdateAnim", 606+id);
        
        new Float:fOrigin[3], Float:fAngle[3], Float:fVelocity[3];
        new Player;
        
        Player = zl_player_random();
    
        pev(id, pev_origin, fOrigin);
        pev(id, pev_view_ofs, fAngle);
        
        fm_velocity_by_aim(2.0, fVelocity, fAngle, Player);
        fAngle[0] *= -1.0;
        
        new ent = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "info_target"));
        
        set_pev(ent, pev_classname, "nst_deimos_skill");
        engfunc(EngFunc_SetModel, ent, "models/w_hegrenade.mdl");
        
        set_pev(ent, pev_mins, Float:{-1.0, -1.0, -1.0});
        set_pev(ent, pev_maxs, Float:{1.0, 1.0, 1.0});
        set_pev(ent, pev_origin, fOrigin);
        
        fOrigin[0] += fVelocity[0];
        fOrigin[1] += fVelocity[1];
        fOrigin[2] += fVelocity[2];
        
        set_pev(ent, pev_movetype, MOVETYPE_BOUNCE);
        set_pev(ent, pev_gravity, 0.01);
        
        fVelocity[0] *= -1000;
        fVelocity[1] *= -1000;
        fVelocity[2] *= -1000;
        
        set_pev(ent, pev_velocity, fVelocity);
        set_pev(ent, pev_owner, id);
        set_pev(ent, pev_angles, fAngle);
        set_pev(ent, pev_solid, SOLID_BBOX);
        
        set_rendering(ent, kRenderFxGlowShell, 0, 0, 0, kRenderTransAlpha, 0);
        
        message_begin(MSG_BROADCAST, SVC_TEMPENTITY);
        write_byte(TE_BEAMFOLLOW);
        write_short(ent);
        write_short(Deimos_Sprite_Line);
        write_byte(5);
        write_byte(3);
        write_byte(209);
        write_byte(120);
        write_byte(9);
        write_byte(200);
        message_end();
        
        engfunc(EngFunc_EmitSound, id, CHAN_VOICE, "citydarkru/zombies/abilityfunc/deimos_start.wav", VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
    }
}

public SkillGhost(id)
{
    id -= 303;
    
    if(pev_valid(id) && pev(id, pev_deadflag) != DEAD_DYING)
    {
        engfunc(EngFunc_EmitSound, id, CHAN_VOICE, "citydarkru/zombies/abilityfunc/invisable_active.wav", VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
        
        set_rendering(id, kRenderFxGlowShell, 0, 0, 0, kRenderTransAlpha, 10);
        
        set_task(5.0, "SkillGhostEnd", 404+id);
    }
}

public SkillGhostEnd(id)
{
    id -= 404;
    
    if(pev_valid(id) && pev(id, pev_deadflag) != DEAD_DYING)
    {
        engfunc(EngFunc_EmitSound, id, CHAN_VOICE, "citydarkru/zombies/abilityfunc/invisable_active.wav", VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
        
        set_rendering(id);
    }
}

public SkillGrenade(id)
{
    id -= 505;
    
    if(pev_valid(id) && (pev(id, pev_deadflag) != DEAD_DYING) && zl_player_alive() > 0)
    {
        Anim(id, 57, 2.0);
        
        set_task(0.5, "SkillUpdateAnim", 606+id);
        
        static Float:StartOrigin[3], Float:TargetOrigin[3], Float:angles[3], Float:angles_fix[3];
    
        get_weapon_position(id, StartOrigin, .add_forward = 30.0, .add_right = 8.0, .add_up = 10.0);
        
        pev(id, pev_v_angle, angles);
        
        static Ent;
        Ent = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "info_target"));
        
        if(!pev_valid(Ent))
            return;
        
        angles_fix[0] = 360.0 - angles[0];
        angles_fix[1] = angles[1];
        angles_fix[2] = angles[2];
        
        set_pev(Ent, pev_movetype, MOVETYPE_TOSS);
        set_pev(Ent, pev_owner, id);
        
        entity_set_string(Ent, EV_SZ_classname, "grenade_skill");
        engfunc(EngFunc_SetModel, Ent, GrenadeMdl);
        set_pev(Ent, pev_body, 1);
        set_pev(Ent, pev_mins, {-0.1, -0.1, -0.1});
        set_pev(Ent, pev_maxs, {0.1, 0.1, 0.1});
        set_pev(Ent, pev_origin, StartOrigin);
        set_pev(Ent, pev_angles, angles_fix);
        set_pev(Ent, pev_gravity, 1.0);
        set_pev(Ent, pev_solid, SOLID_BBOX);
        set_pev(Ent, pev_frame, 0.0);
        
        static Float:Velocity[3];
        static Player;
        
        Player = zl_player_random();
        
        pev(Player, pev_origin, TargetOrigin);
        
        get_speed_vector(StartOrigin, TargetOrigin, 700.0, Velocity);
        
        set_pev(Ent, pev_velocity, Velocity);
    }
}

public SkillUpdateAnim(id)
{
    id -= 606;
    
    if(pev_valid(id) && pev(id, pev_deadflag) != DEAD_DYING)
        Anim(id, 4, 1.0);
}

public Hook_BloodColor(Ent)
{
    if(!native_zl_zmclassic_valid(Ent) && !native_zl_zmdeimos_valid(Ent) && !native_zl_zmghost_valid(Ent) && !native_zl_zmheal_valid(Ent) && !native_zl_zmwitch_valid(Ent) && !native_zl_zmbig_valid(Ent) && !native_zl_zmhound_valid(Ent))
        return HAM_IGNORED;
    
    SetHamReturnInteger(zombie_blood);
    
    return HAM_SUPERCEDE;
}

public fw_Touch(ent, victim)
{
    if(!pev_valid(ent))
        return FMRES_IGNORED;
    
    new EntClassName[32];
    entity_get_string(ent, EV_SZ_classname, EntClassName, charsmax(EntClassName));
    
    if(equal(EntClassName, "nst_deimos_skill"))
    {
        light_exp(ent, victim);
        
        remove_entity(ent);
        
        return FMRES_IGNORED;
    }
    
    return FMRES_IGNORED;
}

light_exp(ent, victim)
{
    if(!pev_valid(ent))
        return;
    
    if(is_user_alive(victim))
    {
        new wpn, wpnname[32];
        wpn = get_user_weapon(victim);
        
        if(!(WPN_NOT_DROP & (1<<wpn)) && get_weaponname(wpn, wpnname, charsmax(wpnname)))
            engclient_cmd(victim, "drop", wpnname);
    }
    
    static Float:origin[3];
    pev(ent, pev_origin, origin);
    
    message_begin(MSG_BROADCAST,SVC_TEMPENTITY);
    write_byte(TE_EXPLOSION);
    write_coord(floatround(origin[0]));
    write_coord(floatround(origin[1]));
    write_coord(floatround(origin[2]));
    write_short(Deimos_Sprite_Exp);
    write_byte(40);
    write_byte(30);
    write_byte(14);
    message_end();
    
    engfunc(EngFunc_EmitSound, ent, CHAN_VOICE, "citydarkru/zombies/abilityfunc/deimos_hit.wav", VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
}

public fw_Weapon_Touch(ent, id)
{
    if(!pev_valid(ent))
        return;
    
    new Float:flOrigin[3];
    pev(ent, pev_origin, flOrigin);
    
    engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, flOrigin, 0);
    write_byte(TE_SPRITE);
    engfunc(EngFunc_WriteCoord,flOrigin[0]);
    engfunc(EngFunc_WriteCoord,flOrigin[1]);
    engfunc(EngFunc_WriteCoord,flOrigin[2] + 45.0);
    write_short(Grenade_Sprite_Exp);
    write_byte(35);
    write_byte(186);
    message_end();

    engfunc(EngFunc_EmitSound, ent, CHAN_VOICE, "weapons/zombie_bomb_exp.wav", VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
    
    for(new i = 1; i <= get_maxplayers(); i++)
    {
        if(!is_user_alive(i))
            continue;
        
        new Float:flVictimOrigin[3];
        pev(i, pev_origin, flVictimOrigin);
        
        new Float:flDistance = get_distance_f(flOrigin, flVictimOrigin);
        
        if(flDistance <= 300.0)
        {
            static Float:flSpeed;
            flSpeed = 800.0;
            
            static Float:flNewSpeed;
            flNewSpeed = flSpeed * (1.0 - (flDistance / 300.0));
            
            static Float:flVelocity[3];
            get_speed_vector(flOrigin, flVictimOrigin, flNewSpeed, flVelocity);
            
            set_pev(i, pev_velocity, flVelocity);
            
            message_begin(MSG_ONE_UNRELIABLE, get_user_msgid("ScreenShake"), _, i);
            write_short((1<<12)*4);
            write_short((1<<12)*10);
            write_short((1<<12)*10);
            message_end();
            
            if(pev(i, pev_health) - 10.0 <= 0)
                ExecuteHamB(Ham_Killed, i, i, 1);
            else
            {
                static Float:Origin[3];
        
                pev(i, pev_origin, Origin);
                
                ExecuteHamB(Ham_TakeDamage, i, 0, i, 10.0, DMG_BLAST);
                
                message_begin(MSG_ONE_UNRELIABLE, get_user_msgid("Damage"), {0,0,0}, i);
                write_byte(0);
                write_byte(100);
                write_long((1<<1));
                engfunc(EngFunc_WriteCoord, Origin[0]);
                engfunc(EngFunc_WriteCoord, Origin[1]);
                engfunc(EngFunc_WriteCoord, Origin[2]);
                message_end();
            }
        }
    }
    
    remove_entity(ent);
}

fm_velocity_by_aim(Float:fDistance, Float:fVelocity[3], Float:fViewAngle[3], Player)
{
    pev(Player, pev_angles, fViewAngle);
    
    fVelocity[0] = floatcos(fViewAngle[1], degrees) * fDistance;
    fVelocity[1] = floatsin(fViewAngle[1], degrees) * fDistance;
    fVelocity[2] = floatcos(fViewAngle[0]+90.0, degrees) * fDistance;
    
    return 1;
}

stock get_weapon_position(id, Float:fOrigin[3], Float:add_forward = 0.0, Float:add_right = 0.0, Float:add_up = 0.0)
{
    static Float:Angles[3], Float:ViewOfs[3], Float:vAngles[3];
    static Float:Forward[3], Float:Right[3], Float:Up[3];
    
    pev(id, pev_v_angle, vAngles);
    pev(id, pev_origin, fOrigin);
    pev(id, pev_view_ofs, ViewOfs);
    
    xs_vec_add(fOrigin, ViewOfs, fOrigin);
    
    pev(id, pev_v_angle, Angles);
    
    engfunc(EngFunc_MakeVectors, Angles);
    
    global_get(glb_v_forward, Forward);
    global_get(glb_v_right, Right);
    global_get(glb_v_up, Up);
    
    xs_vec_mul_scalar(Forward, add_forward, Forward);
    xs_vec_mul_scalar(Right, add_right, Right);
    xs_vec_mul_scalar(Up, add_up, Up);
    
    fOrigin[0] = fOrigin[0] + Forward[0] + Right[0] + Up[0];
    fOrigin[1] = fOrigin[1] + Forward[1] + Right[1] + Up[1];
    fOrigin[2] = fOrigin[2] + Forward[2] + Right[2] + Up[2];
}

stock get_speed_vector(const Float:origin1[3], const Float:origin2[3], Float:speed, Float:new_velocity[3])
{
    new_velocity[0] = origin2[0] - origin1[0];
    new_velocity[1] = origin2[1] - origin1[1];
    new_velocity[2] = origin2[2] - origin1[2];
    
    static Float:num;
    num = floatsqroot(speed * speed / (new_velocity[0] * new_velocity[0] + new_velocity[1] * new_velocity[1] + new_velocity[2] * new_velocity[2]));
    
    new_velocity[0] *= num;
    new_velocity[1] *= num;
    new_velocity[2] *= num;
    
    return 1;
}

stock Heal_Effect(Float:Origin[3])
{
    message_begin(MSG_BROADCAST, SVC_TEMPENTITY);
    write_byte(TE_SPRITE);
    engfunc(EngFunc_WriteCoord, Origin[0]);
    engfunc(EngFunc_WriteCoord, Origin[1]);
    engfunc(EngFunc_WriteCoord, Origin[2] + 45);
    write_short(Healer_Sprite);
    write_byte(15);
    write_byte(255);
    message_end();
}

stock Anim(ent, sequence, Float:speed)
{       
    set_pev(ent, pev_sequence, sequence);
    set_pev(ent, pev_animtime, halflife_time());
    set_pev(ent, pev_framerate, speed);
}

public native_zl_zmclassic_valid(index)
{
    if(!pev_valid(index))
        return 0;
        
    static ClassName[63];
    pev(index, pev_classname, ClassName, charsmax(ClassName));
    
    if(contain(ClassName, "NpcClassic_" ) != -1)
        return 1;
        
    return 0;
}

public native_zl_zmdeimos_valid(index)
{
    if(!pev_valid(index))
        return 0;
        
    static ClassName[63];
    pev(index, pev_classname, ClassName, charsmax(ClassName));
    
    if(contain(ClassName, "NpcDeimos_" ) != -1)
        return 1;
        
    return 0;
}

public native_zl_zmghost_valid(index)
{
    if(!pev_valid(index))
        return 0;
        
    static ClassName[63];
    pev(index, pev_classname, ClassName, charsmax(ClassName));
    
    if(contain(ClassName, "NpcGhost_" ) != -1)
        return 1;
        
    return 0;
}

public native_zl_zmheal_valid(index)
{
    if(!pev_valid(index))
        return 0;
        
    static ClassName[63];
    pev(index, pev_classname, ClassName, charsmax(ClassName));
    
    if(contain(ClassName, "NpcHeal_" ) != -1)
        return 1;
        
    return 0;
}

public native_zl_zmwitch_valid(index)
{
    if(!pev_valid(index))
        return 0;
        
    static ClassName[63];
    pev(index, pev_classname, ClassName, charsmax(ClassName));
    
    if(contain(ClassName, "NpcWitch_" ) != -1)
        return 1;
        
    return 0;
}

public native_zl_zmbig_valid(index)
{
    if(!pev_valid(index))
        return 0;
        
    static ClassName[63];
    pev(index, pev_classname, ClassName, charsmax(ClassName));
    
    if(contain(ClassName, "NpcBig_" ) != -1)
        return 1;
        
    return 0;
}

public native_zl_zmhound_valid(index)
{
    if(!pev_valid(index))
        return 0;
        
    static ClassName[63];
    pev(index, pev_classname, ClassName, charsmax(ClassName));
    
    if(contain(ClassName, "NpcHound_" ) != -1)
        return 1;
        
    return 0;
}

public native_zl_zombie_count() return ZombieCount;

stock zm_damage(id, damage)
{
    if(!is_user_alive(id))
        return;
        
    new hp = pev(id, pev_health);
    
    if(hp - damage <= 0)
        ExecuteHamB(Ham_Killed, id, id, 2);
    else
    {
        static Float:Origin[3];
        
        pev(id, pev_origin, Origin);
        
        ExecuteHamB(Ham_TakeDamage, id, 0, id, float(damage), DMG_BLAST);
        
        message_begin(MSG_ONE_UNRELIABLE, get_user_msgid("Damage"), {0,0,0}, id);
        write_byte(0);
        write_byte(100);
        write_long((1<<1));
        engfunc(EngFunc_WriteCoord, Origin[0]);
        engfunc(EngFunc_WriteCoord, Origin[1]);
        engfunc(EngFunc_WriteCoord, Origin[2]);
        message_end();
    }
}



Что нужно добавить в функцию public Hook_Think(Ent), чтобы модели NPC не застревали при подъеме по склону?
 
Сверху Снизу