#include <amxmodx>
#include <zombieplague>
#include <fakemeta>
#include <hamsandwich>
#include <engine>

#define PLUGIN "Smoker Zombi by sZmolka"
#define VERSION "1.0"
#define AUTHOR "sZmolka"


new g_zclass_smoker, g_Line
new g_sndMiss[] = "zombie_plague/Smoker_TongueHit_miss.wav"
new g_sndDrag[] = "zombie_plague/Smoker_TongueHit_drag.wav"
new g_hooked[33], g_hooksLeft[33], g_unable2move[33], g_ovr_dmg[33]
new Float:g_lastHook[33]
new bool: g_bind_use[33] = false, bool: g_bind_or_not[33] = false, bool: g_drag_i[33] = false
new cvar_maxdrags, cvar_dragspeed, cvar_cooldown, cvar_dmg2stop, cvar_mates, cvar_extrahook, cvar_unb2move, cvar_nemesis, cvar_survivor, cvar_headstop;
new keys = MENU_KEY_1|MENU_KEY_2|MENU_KEY_3

new const zclass_name[] = { "Smoker" }
new const zclass_info[] = { "huzas VIP" }
new const zclass_model[] = { "zombie_red" }
new const zclass_clawmodel[] = { "v_knife_zombie5.mdl" }
const zclass_health = 1700
const zclass_speed = 240
const Float:zclass_gravity = 0.9
const Float:zclass_knockback = 1.0
const zclass_adminflags = ADMIN_KICK

public plugin_init()
{    
    register_dictionary("zp_zclass_smoker.txt");
	cvar_headstop = register_cvar("zp_smoker_headstop", "0");
	RegisterHam(Ham_TraceAttack, "player", "forward_trace_attack");
    
    cvar_dragspeed = register_cvar("zp_smoker_dragspeed", "150")
    cvar_maxdrags = register_cvar("zp_smoker_maxdrags", "15")
    cvar_cooldown = register_cvar("zp_smoker_cooldown", "5")
    cvar_dmg2stop = register_cvar("zp_smoker_dmg2stop", "350")
    cvar_mates = register_cvar("zp_smoker_mates", "0")
    cvar_extrahook = register_cvar("zp_smoker_extrahook", "2")
    cvar_unb2move = register_cvar("zp_smoker_unable_move", "0")
    cvar_nemesis = register_cvar("zp_smoker_nemesis", "0")
    cvar_survivor = register_cvar("zp_smoker_survivor", "1")
    register_event("ResetHUD", "newSpawn", "b")
    register_event("DeathMsg", "smoker_death", "a")
    register_forward(FM_PlayerPreThink, "fw_PlayerPreThink")
    RegisterHam(Ham_TakeDamage, "player", "fw_TakeDamage")
    register_clcmd("+drag","drag_start", ADMIN_USER, "bind ^"key^" ^"+drag^"")
    register_clcmd("-drag","drag_end")
	
	
}
public plugin_precache()
{
    register_plugin(PLUGIN, VERSION, AUTHOR)
    g_zclass_smoker = zp_register_zombie_class(zclass_name, zclass_info, zclass_model, zclass_clawmodel, zclass_health, zclass_speed, zclass_gravity, zclass_knockback)
    precache_sound(g_sndDrag)
    precache_sound(g_sndMiss)
    g_Line = precache_model("sprites/zbeam4.spr")    
}

public forward_trace_attack()
{
	if(!get_pcvar_num(cvar_headstop))
		return PLUGIN_HANDLED;

	new victim = read_data(1);
	new attacker = read_data(2);
	new where = read_data(5);
	
	if(zp_get_user_zombie(victim) && !zp_get_user_zombie(attacker) && (get_tr2(where, TR_iHitgroup) == HIT_HEAD))
	{
		drag_end(victim);
	}
}

public zp_user_infected_post(id, infector)
{
    if ((zp_get_user_zombie_class(infector) == g_zclass_smoker) && (get_pcvar_num(cvar_extrahook) > 0))
    {
        g_hooksLeft[infector] = g_hooksLeft[infector] + get_pcvar_num(cvar_extrahook)
        set_hudmessage(255, 0, 0, -1.0, 0.45, 0, 0.0, 3.0, 0.01, 0.01, -1)
        show_hudmessage(infector, "+%d drag%s!", get_pcvar_num(cvar_extrahook), (get_pcvar_num(cvar_extrahook) < 2) ? "" : "s")
    }
    
    if (zp_get_user_zombie_class(id) == g_zclass_smoker)
    {
        g_hooksLeft[id] = get_pcvar_num(cvar_maxdrags)
        
        if (!g_bind_or_not[id])
        {
            new menu_title[64], menu_yes[32], menu_no[32], menu_use[64], menu_exit[32];
            
            formatex(menu_title, charsmax(menu_title), "\r%L", LANG_SERVER, "SMOKER_MENU_TITLE");
            formatex(menu_yes, charsmax(menu_yes), "\r%L", LANG_SERVER, "SMOKER_MENU_YES");
            formatex(menu_no, charsmax(menu_no), "\r%L", LANG_SERVER, "SMOKER_MENU_NO");
            formatex(menu_use, charsmax(menu_use), "\r%L", LANG_SERVER, "SMOKER_MENU_USE");
            formatex(menu_exit, charsmax(menu_exit), "\r%L", LANG_SERVER, "SMOKER_MENU_EXIT");            
            
            new menu = menu_create(menu_title, "menu_handler");
            
            menu_additem(menu, menu_yes, "1", 0);
            menu_additem(menu, menu_no, "2", 0);
            menu_additem(menu, menu_use, "3", 0);
            
            menu_setprop(menu, MPROP_EXITNAME, menu_exit);

            menu_display(id, menu, 0);
        }
    }
}

public newSpawn(id)
{
    if (g_hooked[id])
        drag_end(id)
}

public drag_start(id) // starts drag, checks if player is Smoker, checks cvars
{        
    if (zp_get_user_zombie(id) && (zp_get_user_zombie_class(id) == g_zclass_smoker) && !g_drag_i[id]) {
        
        static Float:cdown
        cdown = get_pcvar_float(cvar_cooldown)

        if (!is_user_alive(id)) {
            client_print(id, print_chat, "[ZP] %L", id, "CANT_DRAG_DEAD");
            return PLUGIN_HANDLED
        }

        if (g_hooksLeft[id] <= 0) {
            client_print(id, print_chat, "[ZP] %L", id, "CANT_DRAG_ANYMORE");
            return PLUGIN_HANDLED
        }

        if (get_gametime() - g_lastHook[id] < cdown) {
            client_print(id, print_chat, "[ZP] %L", id, "CANT_DRAG_WAIT", get_pcvar_float(cvar_cooldown) - (get_gametime() - g_lastHook[id]));
            return PLUGIN_HANDLED
        }
        
        new hooktarget, body
        get_user_aiming(id, hooktarget, body)
        
        if (zp_get_user_nemesis(id) && get_pcvar_num(cvar_nemesis) == 0) {
            client_print(id, print_chat, "[ZP] %L", id, "CANT_DRAG_NEMESIS");
            return PLUGIN_HANDLED
        }
        
        if (is_user_alive(hooktarget)) {
            if (!zp_get_user_zombie(hooktarget))
                {
                    if (zp_get_user_survivor(hooktarget) && get_pcvar_num(cvar_survivor) == 0) {
                        client_print(id, print_chat, "[ZP] %L", id, "CANT_DRAG_SURVIVOR");
                        return PLUGIN_HANDLED
                    }
                    
                    g_hooked[id] = hooktarget
                    emit_sound(hooktarget, CHAN_BODY, g_sndDrag, 1.0, ATTN_NORM, 0, PITCH_HIGH)
                }
            else
                {
                    if (get_pcvar_num(cvar_mates) == 1)
                    {
                        g_hooked[id] = hooktarget
                        emit_sound(hooktarget, CHAN_BODY, g_sndDrag, 1.0, ATTN_NORM, 0, PITCH_HIGH)
                    }
                    else
                    {
                        client_print(id, print_chat, "[ZP] %L", id, "CANT_DRAG_TEAM");
                        return PLUGIN_HANDLED
                    }
                }

            if (get_pcvar_float(cvar_dragspeed) <= 0.0)
                cvar_dragspeed = 1
            
            new parm[2]
            parm[0] = id
            parm[1] = hooktarget
            
            set_task(0.1, "smoker_reelin", id, parm, 2, "b")
            harpoon_target(parm)
            
            g_hooksLeft[id]--
            client_print(id, print_chat, "[ZP] %L", id, "CAN_DRAG_TIMES", g_hooksLeft[id]);
            g_drag_i[id] = true
            
            if(get_pcvar_num(cvar_unb2move) == 1)
                g_unable2move[hooktarget] = true
                
            if(get_pcvar_num(cvar_unb2move) == 2)
                g_unable2move[id] = true
                
            if(get_pcvar_num(cvar_unb2move) == 3)
            {
                g_unable2move[hooktarget] = true
                g_unable2move[id] = true
            }
        } else {
            g_hooked[id] = 33
            noTarget(id)
            emit_sound(hooktarget, CHAN_BODY, g_sndMiss, 1.0, ATTN_NORM, 0, PITCH_HIGH)
            g_drag_i[id] = true
            g_hooksLeft[id]--
            client_print(id, print_chat, "[ZP] %L", id, "CAN_DRAG_TIMES", g_hooksLeft[id]);
        }
    }
    else
        return PLUGIN_HANDLED
    
    return PLUGIN_CONTINUE
}

public smoker_reelin(parm[]) // dragging player to smoker
{
    new id = parm[0]
    new victim = parm[1]

    if (!g_hooked[id] || !is_user_alive(victim))
    {
        drag_end(id)
        return
    }

    new Float:fl_Velocity[3]
    new idOrigin[3], vicOrigin[3]

    get_user_origin(victim, vicOrigin)
    get_user_origin(id, idOrigin)

    new distance = get_distance(idOrigin, vicOrigin)

    if (distance > 1) {
        new Float:fl_Time = distance / get_pcvar_float(cvar_dragspeed)

        fl_Velocity[0] = (idOrigin[0] - vicOrigin[0]) / fl_Time
        fl_Velocity[1] = (idOrigin[1] - vicOrigin[1]) / fl_Time
        fl_Velocity[2] = (idOrigin[2] - vicOrigin[2]) / fl_Time
    } else {
        fl_Velocity[0] = 0.0
        fl_Velocity[1] = 0.0
        fl_Velocity[2] = 0.0
    }

    entity_set_vector(victim, EV_VEC_velocity, fl_Velocity) //<- rewritten. now uses engine
}

public drag_end(id) // drags end function
{
    g_hooked[id] = 0
    beam_remove(id)
    remove_task(id)
    
    if (g_drag_i[id])
        g_lastHook[id] = get_gametime()
    
    g_drag_i[id] = false
    g_unable2move[id] = false
}

public smoker_death() // if smoker dies drag off
{
    new id = read_data(2)
    
    beam_remove(id)
    
    if (g_hooked[id])
        drag_end(id)
}

public fw_TakeDamage(victim, inflictor, attacker, Float:damage) // if take damage drag off
{
    if (is_user_alive(attacker) && (get_pcvar_num(cvar_dmg2stop) > 0))
    {
        g_ovr_dmg[victim] = g_ovr_dmg[victim] + floatround(damage)
        if (g_ovr_dmg[victim] >= get_pcvar_num(cvar_dmg2stop))
        {
            g_ovr_dmg[victim] = 0
            drag_end(victim)
            return HAM_IGNORED;
        }
    }

    return HAM_IGNORED;
}

public fw_PlayerPreThink(id)
{
    if (!is_user_alive(id))
        return FMRES_IGNORED
    
    new button = get_user_button(id)
    new oldbutton = get_user_oldbutton(id)
    
    if (g_bind_use[id] && zp_get_user_zombie(id) && (zp_get_user_zombie_class(id) == g_zclass_smoker))
    {
        if (!(oldbutton & IN_USE) && (button & IN_USE))
            drag_start(id)
        
        if ((oldbutton & IN_USE) && !(button & IN_USE))
            drag_end(id)
    }
    
    if (!g_drag_i[id]) {
        g_unable2move[id] = false
    }
        
    if (g_unable2move[id] && get_pcvar_num(cvar_unb2move) > 0)
    {
        set_pev(id, pev_maxspeed, 1.0)
    }
    
    return PLUGIN_CONTINUE
}

public client_disconnect(id) // if client disconnects drag off
{
    if (id <= 0 || id > 32)
        return
    
    if (g_hooked[id])
        drag_end(id)
    
    if(g_unable2move[id])
        g_unable2move[id] = false
}

public harpoon_target(parm[]) // set beam (ex. tongue:) if target is player
{
    new id = parm[0]
    new hooktarget = parm[1]

    message_begin(MSG_BROADCAST, SVC_TEMPENTITY)
    write_byte(8)    // TE_BEAMENTS
    write_short(id)
    write_short(hooktarget)
    write_short(g_Line)    // sprite index
    write_byte(0)    // start frame
    write_byte(0)    // framerate
    write_byte(200)    // life
    write_byte(8)    // width
    write_byte(1)    // noise
    write_byte(155)    // r, g, b
    write_byte(155)    // r, g, b
    write_byte(55)    // r, g, b
    write_byte(90)    // brightness
    write_byte(10)    // speed
    message_end()
}

public noTarget(id) // set beam if target isn't player
{
    new endorigin[3]

    get_user_origin(id, endorigin, 3)

    message_begin(MSG_BROADCAST, SVC_TEMPENTITY)
    write_byte( TE_BEAMENTPOINT ); // TE_BEAMENTPOINT
    write_short(id)
    write_coord(endorigin[0])
    write_coord(endorigin[1])
    write_coord(endorigin[2])
    write_short(g_Line) // sprite index
    write_byte(0)    // start frame
    write_byte(0)    // framerate
    write_byte(200)    // life
    write_byte(8)    // width
    write_byte(1)    // noise
    write_byte(155)    // r, g, b
    write_byte(155)    // r, g, b
    write_byte(55)    // r, g, b
    write_byte(75)    // brightness
    write_byte(0)    // speed
    message_end()
}

public beam_remove(id) // remove beam
{
    message_begin(MSG_BROADCAST, SVC_TEMPENTITY)
    write_byte(99)    //TE_KILLBEAM
    write_short(id)    //entity
    message_end()
}

public menu_handler(id, menu, item)
{
    if(item == MENU_EXIT)
    {
        client_print(id, print_chat, "[ZP] %L", id, "BIND_BUTTONS");
        
        menu_destroy(menu);
        return PLUGIN_HANDLED;
    }

    new data[6], name[64], access, callback;

    menu_item_getinfo(menu, item, access, data, charsmax(data), name, charsmax(name), callback);

    new key = str_to_num(data);

    switch(key)
    {
        case 1:
            client_cmd(id, "bind v ^"+drag^"");
        case 2:
            client_print(id, print_chat, "[ZP] %L", id, "BIND_BUTTONS");
        case 3:
            g_bind_use[id] = true;
        default:
            g_bind_or_not[id] = false;            
    }

    menu_destroy(menu);
    return PLUGIN_HANDLED;
}  
/* AMXX-Studio Notes - DO NOT MODIFY BELOW HERE
*{\\ rtf1\\ ansi\\ deff0{\\ fonttbl{\\ f0\\ fnil Tahoma;}}\n\\ viewkind4\\ uc1\\ pard\\ lang1049\\ f0\\ fs16 \n\\ par }
*/
