#include <amxmodx>
#include <amxmisc>
#include <cstrike>
#include <engine>
#include <fakemeta>
#include <hamsandwich>
#include <xs>

#define PLUGIN  "Warfare: Gadgets (JumpPad, EMP Jammer, LaserMine)"
#define VERSION "1.0"
#define AUTHOR  "Antigravity"

new const CLASS_JUMPPAD[]  = "wf_jumppad";
new const CLASS_EMP[]      = "wf_emp";
new const CLASS_TRIPMINE[] = "wf_tripmine";

new g_sprRing;
new g_sprExplo;

new g_iJumpPads[33];
new g_iTripMines[33];
new g_iEmpJammers[33];

new Float:g_vecSpawns[128][3];
new g_iSpawnCount = 0;

stock CacheSpawnPoints() {
    g_iSpawnCount = 0;
    new const szClasses[][] = {
        "info_player_start",
        "info_player_deathmatch",
        "info_vip_start"
    };
    for (new c = 0; c < sizeof(szClasses); c++) {
        new ent = -1;
        while ((ent = engfunc(EngFunc_FindEntityByString, ent, "classname", szClasses[c])) != 0) {
            if (pev_valid(ent) && g_iSpawnCount < sizeof(g_vecSpawns)) {
                pev(ent, pev_origin, g_vecSpawns[g_iSpawnCount]);
                g_iSpawnCount++;
            }
        }
    }
}

stock bool:IsNearSpawnPoint(const Float:orig[3], Float:radius) {
    if (g_iSpawnCount == 0) {
        CacheSpawnPoints();
    }
    for (new i = 0; i < g_iSpawnCount; i++) {
        if (get_distance_f(orig, g_vecSpawns[i]) <= radius) {
            return true;
        }
    }
    return false;
}


public plugin_init() {
    CacheSpawnPoints();
    register_plugin(PLUGIN, VERSION, AUTHOR);

    register_touch(CLASS_JUMPPAD, "player", "Touch_JumpPad");
    register_think(CLASS_EMP, "fw_EmpThink");
    register_think(CLASS_TRIPMINE, "fw_TripmineThink");
    RegisterHam(Ham_TakeDamage, "info_target", "fw_GadgetTakeDamage");
    RegisterHam(Ham_Killed, "player", "fw_PlayerKilled_Post", 1);

    register_clcmd("say /gadgets", "Cmd_GadgetsMenu");
    register_clcmd("say /gadget", "Cmd_GadgetsMenu");
    register_clcmd("say /pad", "Cmd_BuildPad");
    register_clcmd("say /jumper", "Cmd_BuildPad");
    register_clcmd("say /mine", "Cmd_BuildMine");
    register_clcmd("say /laser", "Cmd_BuildMine");
    register_clcmd("say /emp", "Cmd_BuildEmp");
}

public plugin_precache() {
    precache_sound("buttons/button10.wav");
    g_sprRing  = precache_model("sprites/shockwave.spr");
    g_sprExplo = precache_model("sprites/fexplo.spr");
}

public client_putinserver(id) {
    g_iJumpPads[id] = 0;
    g_iTripMines[id] = 0;
    g_iEmpJammers[id] = 0;
}

public client_disconnected(id) {
    RemovePlayerGadgets(id);
}

stock RemovePlayerGadgets(id) {
    new const classes[][] = { "wf_jumppad", "wf_emp", "wf_tripmine" };
    for (new i = 0; i < sizeof(classes); i++) {
        new to_del[16], count = 0;
        new ent = -1;
        while ((ent = engfunc(EngFunc_FindEntityByString, ent, "classname", classes[i])) != 0) {
            if (pev_valid(ent) && pev(ent, pev_iuser1) == id && count < sizeof(to_del)) {
                to_del[count++] = ent;
            }
        }
        for (new j = 0; j < count; j++) {
            if (pev_valid(to_del[j])) {
                engfunc(EngFunc_RemoveEntity, to_del[j]);
            }
        }
    }
    g_iJumpPads[id] = 0;
    g_iTripMines[id] = 0;
    g_iEmpJammers[id] = 0;
}

public Cmd_GadgetsMenu(id) {
    if (!is_user_alive(id)) {
        client_print(id, print_chat, "[!] Вы должны быть живы для создания гаджетов!");
        return PLUGIN_HANDLED;
    }

    new menu = menu_create("\y[WARFARE ГАДЖЕТЫ] \wТактический арсенал:", "GadgetsMenu_Handler");
    menu_additem(menu, "Прыжковый батут (Джампер) \y[$500]", "1");
    menu_additem(menu, "Лазерная мина-растяжка \y[$600]", "2");
    menu_additem(menu, "ЭМИ-Глушилка электроники \y[$1200]", "3");
    menu_additem(menu, "\rУбрать все свои гаджеты", "4");

    menu_setprop(menu, MPROP_EXITNAME, "Закрыть");
    menu_display(id, menu, 0);
    return PLUGIN_HANDLED;
}

public GadgetsMenu_Handler(id, menu, item) {
    if (item == MENU_EXIT) {
        menu_destroy(menu);
        return PLUGIN_HANDLED;
    }

    new szData[6], szName[64], access, callback;
    menu_item_getinfo(menu, item, access, szData, charsmax(szData), szName, charsmax(szName), callback);
    new choice = str_to_num(szData);
    menu_destroy(menu);

    switch (choice) {
        case 1: Cmd_BuildPad(id);
        case 2: Cmd_BuildMine(id);
        case 3: Cmd_BuildEmp(id);
        case 4: {
            RemovePlayerGadgets(id);
            client_print(id, print_chat, "[ГАДЖЕТЫ] Все ваши гаджеты успешно убраны!");
        }
    }
    return PLUGIN_HANDLED;
}

// -------------------------------------------------------------
// GADGET 1: JUMP PAD
// -------------------------------------------------------------
public Cmd_BuildPad(id) {
    if (!is_user_alive(id)) return PLUGIN_HANDLED;

    new money = cs_get_user_money(id);
    if (money < 500) {
        client_print(id, print_chat, "[!] Недостаточно средств ($500). У вас: $%d", money);
        return PLUGIN_HANDLED;
    }
    if (g_iJumpPads[id] >= 2) {
        client_print(id, print_chat, "[!] Достигнут лимит батутов (макс: 2)!");
        return PLUGIN_HANDLED;
    }

    new Float:orig[3];
    pev(id, pev_origin, orig);

    if (IsNearSpawnPoint(orig, 400.0)) {
        client_print(id, print_chat, "[ГАДЖЕТЫ] Запрещено устанавливать гаджеты в зоне спавна!");
        emit_sound(id, CHAN_ITEM, "buttons/button10.wav", 0.8, ATTN_NORM, 0, PITCH_NORM);
        return PLUGIN_HANDLED;
    }

    orig[2] -= 25.0;

    new ent = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "info_target"));
    if (!pev_valid(ent)) return PLUGIN_HANDLED;

    set_pev(ent, pev_classname, CLASS_JUMPPAD);
    engfunc(EngFunc_SetModel, ent, "models/pallet_with_bags2.mdl");
    set_pev(ent, pev_origin, orig);
    set_pev(ent, pev_solid, SOLID_TRIGGER);
    set_pev(ent, pev_movetype, MOVETYPE_NONE);
    set_pev(ent, pev_iuser1, id);
    set_pev(ent, pev_iuser2, _:cs_get_user_team(id));
    engfunc(EngFunc_SetSize, ent, Float:{-30.0, -30.0, 0.0}, Float:{30.0, 30.0, 20.0});

    cs_set_user_money(id, money - 500);
    g_iJumpPads[id]++;
    client_print(id, print_chat, "[ГАДЖЕТЫ] Прыжковый батут установлен! Наступите для высокого взлёта.");
    return PLUGIN_HANDLED;
}

public Touch_JumpPad(pad, player) {
    if (!pev_valid(pad) || !is_user_alive(player)) return;

    new Float:now = get_gametime();
    new Float:last_jump;
    pev(pad, pev_fuser1, last_jump);
    if (now - last_jump < 0.8) return; // Cooldown
    set_pev(pad, pev_fuser1, now);

    new Float:v_angle[3], Float:fwd[3];
    pev(player, pev_v_angle, v_angle);
    v_angle[0] = 0.0;
    angle_vector(v_angle, ANGLEVECTOR_FORWARD, fwd);

    new Float:vel[3];
    vel[0] = fwd[0] * 380.0;
    vel[1] = fwd[1] * 380.0;
    vel[2] = 580.0; // High bounce upward!

    set_pev(player, pev_velocity, vel);

    // Green launch ring
    new Float:p_orig[3];
    pev(player, pev_origin, p_orig);

    message_begin(MSG_BROADCAST, SVC_TEMPENTITY);
    write_byte(TE_BEAMCYLINDER);
    write_coord(floatround(p_orig[0]));
    write_coord(floatround(p_orig[1]));
    write_coord(floatround(p_orig[2]));
    write_coord(floatround(p_orig[0]));
    write_coord(floatround(p_orig[1]));
    write_coord(floatround(p_orig[2] + 40.0));
    write_short(g_sprRing);
    write_byte(0);
    write_byte(10);
    write_byte(3);
    write_byte(15);
    write_byte(0);
    write_byte(0); write_byte(255); write_byte(100);
    write_byte(200);
    write_byte(0);
    message_end();
}

// -------------------------------------------------------------
// GADGET 2: LASER TRIPMINE
// -------------------------------------------------------------
public Cmd_BuildMine(id) {
    if (!is_user_alive(id)) return PLUGIN_HANDLED;

    new money = cs_get_user_money(id);
    if (money < 600) {
        client_print(id, print_chat, "[!] Недостаточно средств ($600). У вас: $%d", money);
        return PLUGIN_HANDLED;
    }
    if (g_iTripMines[id] >= 3) {
        client_print(id, print_chat, "[!] Достигнут лимит лазерных мин (макс: 3)!");
        return PLUGIN_HANDLED;
    }

    new Float:orig[3];
    pev(id, pev_origin, orig);

    if (IsNearSpawnPoint(orig, 400.0)) {
        client_print(id, print_chat, "[ГАДЖЕТЫ] Запрещено устанавливать гаджеты в зоне спавна!");
        emit_sound(id, CHAN_ITEM, "buttons/button10.wav", 0.8, ATTN_NORM, 0, PITCH_NORM);
        return PLUGIN_HANDLED;
    }

    new ent = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "info_target"));
    if (!pev_valid(ent)) return PLUGIN_HANDLED;

    set_pev(ent, pev_classname, CLASS_TRIPMINE);
    engfunc(EngFunc_SetModel, ent, "models/w_c4.mdl");
    set_pev(ent, pev_origin, orig);
    set_pev(ent, pev_solid, SOLID_BBOX);
    set_pev(ent, pev_takedamage, DAMAGE_YES);
    set_pev(ent, pev_movetype, MOVETYPE_TOSS);
    set_pev(ent, pev_health, 300.0);
    set_pev(ent, pev_takedamage, DAMAGE_YES);
    set_pev(ent, pev_iuser1, id);
    set_pev(ent, pev_iuser2, _:cs_get_user_team(id));
    set_pev(ent, pev_nextthink, get_gametime() + 0.1);

    cs_set_user_money(id, money - 600);
    g_iTripMines[id]++;
    client_print(id, print_chat, "[ГАДЖЕТЫ] Лазерная мина установлена! Враг в радиусе 120 единиц подорвётся.");
    return PLUGIN_HANDLED;
}

public fw_TripmineThink(ent) {
    if (!pev_valid(ent)) return;

    new Float:orig[3];
    pev(ent, pev_origin, orig);
    new team = pev(ent, pev_iuser2);
    new owner = pev(ent, pev_iuser1);

    // Check for nearby enemies
    for (new i = 1; i <= MaxClients; i++) {
        if (!is_user_alive(i) || _:cs_get_user_team(i) == team) continue;

        new Float:p_orig[3];
        pev(i, pev_origin, p_orig);
        if (get_distance_f(orig, p_orig) <= 120.0) {
            // DETONATE MINE!
            message_begin(MSG_BROADCAST, SVC_TEMPENTITY);
            write_byte(TE_EXPLOSION);
            write_coord(floatround(orig[0]));
            write_coord(floatround(orig[1]));
            write_coord(floatround(orig[2] + 15.0));
            write_short(g_sprExplo);
            write_byte(35);
            write_byte(25);
            write_byte(0);
            message_end();

            ExecuteHamB(Ham_TakeDamage, i, owner, owner, 250.0, DMG_BLAST);
            engfunc(EngFunc_RemoveEntity, ent);
            return;
        }
    }

    set_pev(ent, pev_nextthink, get_gametime() + 0.15);
}

// -------------------------------------------------------------
// GADGET 3: EMP JAMMER
// -------------------------------------------------------------
public Cmd_BuildEmp(id) {
    if (!is_user_alive(id)) return PLUGIN_HANDLED;

    new money = cs_get_user_money(id);
    if (money < 1200) {
        client_print(id, print_chat, "[!] Недостаточно средств ($1200). У вас: $%d", money);
        return PLUGIN_HANDLED;
    }
    if (g_iEmpJammers[id] >= 1) {
        client_print(id, print_chat, "[!] Достигнут лимит ЭМИ-глушилок (макс: 1)!");
        return PLUGIN_HANDLED;
    }

    new Float:orig[3];
    pev(id, pev_origin, orig);

    if (IsNearSpawnPoint(orig, 400.0)) {
        client_print(id, print_chat, "[ГАДЖЕТЫ] Запрещено устанавливать гаджеты в зоне спавна!");
        emit_sound(id, CHAN_ITEM, "buttons/button10.wav", 0.8, ATTN_NORM, 0, PITCH_NORM);
        return PLUGIN_HANDLED;
    }

    new ent = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "info_target"));
    if (!pev_valid(ent)) return PLUGIN_HANDLED;

    set_pev(ent, pev_classname, CLASS_EMP);
    engfunc(EngFunc_SetModel, ent, "models/dispenserby82reg/bank_new.mdl");
    set_pev(ent, pev_origin, orig);
    set_pev(ent, pev_solid, SOLID_BBOX);
    set_pev(ent, pev_movetype, MOVETYPE_TOSS);
    set_pev(ent, pev_iuser1, id);
    set_pev(ent, pev_iuser2, _:cs_get_user_team(id));
    set_pev(ent, pev_nextthink, get_gametime() + 1.0);

    cs_set_user_money(id, money - 1200);
    g_iEmpJammers[id]++;
    client_print(id, print_chat, "[ГАДЖЕТЫ] ЭМИ-Глушилка развернута! Каждые 3 сек глушит вражеские дроны и технику.");
    return PLUGIN_HANDLED;
}

public fw_EmpThink(ent) {
    if (!pev_valid(ent)) return;

    new Float:orig[3];
    pev(ent, pev_origin, orig);

    // Blue electric pulse
    message_begin(MSG_BROADCAST, SVC_TEMPENTITY);
    write_byte(TE_BEAMCYLINDER);
    write_coord(floatround(orig[0]));
    write_coord(floatround(orig[1]));
    write_coord(floatround(orig[2]));
    write_coord(floatround(orig[0]));
    write_coord(floatround(orig[1]));
    write_coord(floatround(orig[2] + 60.0));
    write_short(g_sprRing);
    write_byte(0);
    write_byte(10);
    write_byte(4);
    write_byte(15);
    write_byte(0);
    write_byte(0); write_byte(150); write_byte(255);
    write_byte(200);
    write_byte(0);
    message_end();

    set_pev(ent, pev_nextthink, get_gametime() + 3.0);
}


stock DetonateTripmine(ent) {
    if (!pev_valid(ent)) return;

    new Float:orig[3];
    pev(ent, pev_origin, orig);
    new owner = pev(ent, pev_iuser1);
    new team = pev(ent, pev_iuser2);

    message_begin(MSG_BROADCAST, SVC_TEMPENTITY);
    write_byte(TE_EXPLOSION);
    write_coord(floatround(orig[0]));
    write_coord(floatround(orig[1]));
    write_coord(floatround(orig[2] + 15.0));
    write_short(g_sprExplo);
    write_byte(35);
    write_byte(25);
    write_byte(0);
    message_end();

    // Damage enemies in 160 radius
    for (new i = 1; i <= MaxClients; i++) {
        if (!is_user_alive(i) || _:cs_get_user_team(i) == team) continue;
        new Float:p_orig[3];
        pev(i, pev_origin, p_orig);
        if (get_distance_f(orig, p_orig) <= 160.0) {
            ExecuteHamB(Ham_TakeDamage, i, owner, owner, 250.0, DMG_BLAST);
        }
    }

    if (owner > 0) g_iTripMines[owner] = max(0, g_iTripMines[owner] - 1);
    engfunc(EngFunc_RemoveEntity, ent);
}

public fw_GadgetTakeDamage(victim, inflictor, attacker, Float:damage, damage_type) {
    if (!pev_valid(victim)) return HAM_IGNORED;

    new classname[32];
    pev(victim, pev_classname, classname, charsmax(classname));

    if (!equal(classname, CLASS_EMP) && !equal(classname, CLASS_TRIPMINE)) {
        return HAM_IGNORED;
    }

    new v_team = pev(victim, pev_iuser2);
    new a_team = 0;
    if (attacker > 0 && attacker <= MaxClients && is_user_connected(attacker)) {
        a_team = _:cs_get_user_team(attacker);
    } else if (pev_valid(inflictor)) {
        a_team = pev(inflictor, pev_iuser2);
    }
    if (a_team == v_team) {
        return HAM_SUPERCEDE; // Prevent friendly fire
    }

    if (equal(classname, CLASS_TRIPMINE)) {
        DetonateTripmine(victim);
        return HAM_SUPERCEDE;
    }

    if (equal(classname, CLASS_EMP)) {
        new Float:hp;
        pev(victim, pev_health, hp);
        hp -= damage;
        if (hp <= 0.0) {
            new owner = pev(victim, pev_iuser1);
            if (owner > 0) g_iEmpJammers[owner] = max(0, g_iEmpJammers[owner] - 1);

            new Float:orig[3];
            pev(victim, pev_origin, orig);

            message_begin(MSG_BROADCAST, SVC_TEMPENTITY);
            write_byte(TE_EXPLOSION);
            write_coord(floatround(orig[0]));
            write_coord(floatround(orig[1]));
            write_coord(floatround(orig[2] + 15.0));
            write_short(g_sprExplo);
            write_byte(25);
            write_byte(20);
            write_byte(0);
            message_end();

            if (attacker > 0 && attacker <= MaxClients && is_user_connected(attacker)) {
                cs_set_user_money(attacker, min(16000, cs_get_user_money(attacker) + 400));
                client_print(attacker, print_chat, "[ГАДЖЕТЫ] Уничтожен вражеский генератор помех (ЭМИ)! +$400");
            }
            if (owner > 0 && is_user_connected(owner)) {
                client_print(owner, print_chat, "[ГАДЖЕТЫ] Ваша ЭМИ-глушилка уничтожена!");
            }

            engfunc(EngFunc_RemoveEntity, victim);
            return HAM_SUPERCEDE;
        }
        set_pev(victim, pev_health, hp);
        return HAM_HANDLED;
    }

    return HAM_IGNORED;
}


public fw_PlayerKilled_Post(victim, attacker, shouldgib) {
    if (victim > 0 && victim <= MaxClients) {
        RemovePlayerGadgets(victim);
    }
}
