//-----------
// [ZL] ZombieSystem
//
// NPC Forum
// http://zombielite.Ru/
//--
// By Alexander.3
// http://Alexander3.Ru/
 
#include < amxmodx >
#include < engine >
#include < hamsandwich >
#include < fakemeta >
#include < xs >
 
#define NAME                    "[ZL] ZombieSystem"
#define VERSION                 "1.3 \ 0.1 (Not Testing)"
#define AUTHOR                  "Alexander.3 \ Chrescoe1"
 
new const ZombieMdl[] =                 "models/zl/npc/zombie/classic.mdl"
 
const zombie_limit =            30
const Float:time_delete =       5.0
const NPC_DMIN   = 5
const NPC_DMAX   = 15
 
native zl_player_random()
native zl_boss_map()
 
new const SoundList[][] =
{
        "zl/npc/zombie/die1.wav",
        "zl/npc/zombie/die2.wav",
        "zl/npc/zombie/pain1.wav",
        "zl/npc/zombie/pain2.wav",
        "zl/npc/zombie/pain3.wav",
        "cybertron/zombie/all/miss_slash_02.wav"  
}
static Float:Speed
static ZombieNpc[zombie_limit],Npc_Attack[zombie_limit]
static ZombieNum, ZombieCount
 
static
Float:EntOrigin[3],
Float:VictimOrigin[3],
Float:distansion,
Float:angles[3]
 
new Blood1,Blood2,gibs_1,gibs_2,gibs_3
 
public plugin_init()
{
        register_plugin(NAME, VERSION, AUTHOR)
        if (!zl_boss_map())return
       
       
        RegisterHam(Ham_Think, "info_target", "Hook_Think")
        RegisterHam(Ham_Killed, "info_target", "Hook_Killed")
        RegisterHam(Ham_TakeDamage, "info_target", "npc_TakeDamage")
}
public npc_TakeDamage(victim, weapon, attacker, Float:damage, damagetype)
{
        if(native_zl_zombie_valid(victim))
        {
               
                if(is_user_connected(attacker))
                        client_print(attacker,print_center,"Zycie: %d",pev(victim, pev_health)-floatround(damage))
               
                pev(victim, pev_origin, EntOrigin)
                Blood(true, EntOrigin)
               
                engfunc(EngFunc_EmitSound, victim, CHAN_VOICE, SoundList[_:random_num(6,6)], VOL_NORM, ATTN_NORM, 0, PITCH_NORM)
        }
}
public plugin_precache()
{
        Blood1 = precache_model("sprites/blood.spr")
        Blood2 = precache_model("sprites/bloodspray.spr")
       
        gibs_1 = precache_model("models/fleshgibs.mdl")
        gibs_2 = precache_model("models/bonegibs.mdl")
        gibs_3 = precache_model("models/hgibs.mdl")
       
        precache_model(ZombieMdl)
       
        for (new i; i < sizeof SoundList; ++i)
                precache_sound(SoundList[i])
}
 
 
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, "info_target"))
               
        engfunc(EngFunc_SetModel, ZombieNpc[ZombieNum], ZombieMdl)
        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), "NpcZombie_%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))
        set_pev(ZombieNpc[ZombieNum], pev_deadflag, DEAD_NO)
        set_pev(ZombieNpc[ZombieNum], pev_iuser1,ZombieNum)
       
        set_pev(ZombieNpc[ZombieNum], pev_nextthink, get_gametime() + 0.1)
       
        Speed = float(speed)
       
        drop_to_floor(ZombieNpc[ZombieNum])
        Anim(ZombieNpc[ZombieNum], 76, 10.5)
       
        ZombieCount++
}
 
public Hook_Think(Ent)
{
 
        if (!pev_valid(Ent))return HAM_IGNORED
        if (!native_zl_zombie_valid(Ent))return HAM_IGNORED
        if (pev(Ent, pev_deadflag) == DEAD_DYING)return HAM_IGNORED
               
        static victim
        if (!is_user_alive(victim))
        {
                victim = zl_player_random()
                set_pev(Ent, pev_nextthink, get_gametime() + 0.2)
                return HAM_HANDLED
        }
        pev(Ent, pev_origin, EntOrigin)
        pev(victim, pev_origin, VictimOrigin)
        distansion= get_distance_f(EntOrigin, VictimOrigin)
       
        new npcnumber = pev(Ent,pev_iuser1)
        if(Npc_Attack[npcnumber]==1)
                ability_attack(Ent,victim)
        else
        if(distansion < 50.0)
                ability_attack(Ent,victim)
        else
                ability_walk(Ent,victim)
       
        return HAM_HANDLED
}
public ability_attack(ent,victim)
{
        new npcnumber = pev(ent,pev_iuser1)
        switch(Npc_Attack[npcnumber])
        {
                case 0:
                {
                        Npc_Attack[npcnumber]=1
                        set_pev(ent, pev_movetype, MOVETYPE_NONE)
                        Anim(ent,76,1.0)
                        engfunc(EngFunc_EmitSound, victim, CHAN_VOICE, SoundList[_:random_num(3,5)], VOL_NORM, ATTN_NORM, 0, PITCH_NORM)
                        pev(victim, pev_origin, VictimOrigin)
                        aim_at_origin(ent, VictimOrigin, angles)
                        angles[0] = 0.0
                        set_pev(ent, pev_angles, angles)
                        set_pev(ent, pev_nextthink, get_gametime() + 0.25)
                        return
                }
                case 1:
                {
                        Npc_Attack[npcnumber]++
                        pev(ent, pev_origin, EntOrigin)
                        pev(victim,pev_origin, VictimOrigin)
                        distansion= get_distance_f(EntOrigin, VictimOrigin)
                        if(distansion < 60.0)
                        {
                                ExecuteHam(Ham_TakeDamage, victim, 0, 0, random_float(float(NPC_DMIN),float(NPC_DMAX)), DMG_BULLET)
                                ScreenFade(victim,4,255,55,55,155)
                                ScreenShake(victim, ((1<<12) *2), ((2<<12) * 3))
                        }
                        set_pev(ent, pev_nextthink, get_gametime() + 0.45)
                        return
                }
        }
        set_pev(ent, pev_movetype, MOVETYPE_PUSHSTEP)
        Npc_Attack[npcnumber]=0
        set_pev(ent, pev_nextthink, get_gametime() + 0.1)
}
public ability_walk(Ent,id)
{
        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(id, 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_zombie_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)
        Anim(victim, random_num(101, 110), 1.0)
        set_task(time_delete, "Zombie_Delete", victim)
        */
        pev(victim, pev_origin, EntOrigin)
        Gibs(EntOrigin,gibs_1,4,5)
        Gibs(EntOrigin,gibs_2,5,5)
        Gibs(EntOrigin,gibs_3,11,5)
        Zombie_Delete(victim)
       
        engfunc(EngFunc_EmitSound, victim, CHAN_VOICE, SoundList[_:random_num(3,5)], VOL_NORM, ATTN_NORM, 0, PITCH_NORM)
       
        return HAM_SUPERCEDE
}
 
public Zombie_Delete(id)
{
        engfunc(EngFunc_RemoveEntity, id)
        ZombieCount--
}
 
//Natives
public plugin_natives()
{
        register_native("zl_zombie_valid", "native_zl_zombie_valid", 1)
        register_native("zl_zombie_count", "native_zl_zombie_count", 1)
        register_native("zl_zombie_create", "native_zl_zombie_create", 1)
}
public native_zl_zombie_valid(index)
{
        if (!pev_valid(index))return 0
               
        static ClassName[63]
        pev(index, pev_classname, ClassName, charsmax(ClassName))
       
        if (contain(ClassName, "NpcZombie_" ) != -1) return 1
        return 0
}
public native_zl_zombie_count()
        return ZombieCount
 
//Stocks
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)
}
stock ScreenFade(id, Timer, Colors1, Colors2, Colors3, Alpha)
{
        if(!is_user_connected(id)) return
       
        message_begin(MSG_ONE_UNRELIABLE, get_user_msgid("ScreenFade"), _, id);
        write_short((1<<12) * Timer)
        write_short( 14<<18 )
        write_short( 1<<1 )    
        write_byte(Colors1)
        write_byte(Colors2)
        write_byte(Colors3)
        write_byte(Alpha)
        message_end()
}
stock ScreenShake(id, duration, frequency)
{
        if(!is_user_alive(id)) return
       
        message_begin(MSG_ONE_UNRELIABLE, get_user_msgid("ScreenShake"), _, id);
        write_short(1<<14)
        write_short(duration)
        write_short(frequency)
        message_end();
}
stock Blood(bool:What, Float:Orig[3])
{      
        message_begin(MSG_BROADCAST, SVC_TEMPENTITY);
        write_byte(TE_BLOODSPRITE);
        engfunc(EngFunc_WriteCoord, Orig[0])
        engfunc(EngFunc_WriteCoord, Orig[1])
        engfunc(EngFunc_WriteCoord, Orig[2])
        write_short(Blood1)
        write_short(Blood2)
        write_byte(228)
        write_byte(What ? random_num(1, 2) : 6)
        message_end();
}
stock aim_at_origin(id, Float:target[3], Float:angles[3])
{
        static Float:vec[3]
        pev(id, pev_origin, vec)
        vec[0] = target[0] - vec[0]
        vec[1] = target[1] - vec[1]
        vec[2] = target[2] - vec[2]
        engfunc(EngFunc_VecToAngles, vec, angles)
        angles[0] *= -1.0, angles[2] = 0.0
}
stock Gibs(Float:Origin[3],model,count,velocity)
{
        //Gibs
        message_begin(MSG_BROADCAST,SVC_TEMPENTITY);
        write_byte(TE_BREAKMODEL); // TE_
        engfunc(EngFunc_WriteCoord, Origin[0])
        engfunc(EngFunc_WriteCoord, Origin[1])
        engfunc(EngFunc_WriteCoord, Origin[2]+24.0)
        write_coord(16); // size X
        write_coord(16); // size Y
        write_coord(16); // size Z
        write_coord(random_num(-velocity,velocity)); // velocity X
        write_coord(random_num(-velocity,velocity)); // velocity Y
        write_coord(25); // velocity Z
        write_byte(10); // random velocity
        write_short(model); // sprite
        write_byte(count); // count
        write_byte(20); // life
        write_byte(0x04); // flags
        message_end();  
}
/* AMXX-Studio Notes - DO NOT MODIFY BELOW HERE
*{\\ rtf1\\ ansi\\ deff0{\\ fonttbl{\\ f0\\ fnil Tahoma;}}\n\\ viewkind4\\ uc1\\ pard\\ lang1049\\ f0\\ fs16 \n\\ par }
*/