#include <amxmodx>
#include <amxmisc>
#include <cstrike>
#include <fakemeta>
#include <engine>

#define PLUGIN  "Warfare: Building Semiclip, Repair & Anti-Block"
#define VERSION "1.0"
#define AUTHOR  "Antigravity"

new g_cvarEnable;

// [0] = Terrorist, [1] = CT
new g_iFriendlyBuildings[2][64];
new g_iFriendlyCount[2];

new Float:g_flLastRepairHUD[33];
new Float:g_flNextRepairTime[33];

new const g_szBuildingClasses[][] = {
    "wf_sentry",
    "wf_pvo",
    "wf_net_pillar",
    "wf_barricade",
    "wf_tesla",
    "wf_dispenser",
    "wf_generator",
    "wf_rszo",
    "wf_emp",
    "wf_tripmine"
};

public plugin_init() {
    register_plugin(PLUGIN, VERSION, AUTHOR);

    g_cvarEnable = register_cvar("wf_building_semiclip", "1");

    set_task(0.25, "Task_RefreshBuildings", .flags = "b");
}

public client_putinserver(id) {
    g_flLastRepairHUD[id] = 0.0;
    g_flNextRepairTime[id] = 0.0;
}

stock GetBuildingNiceName(const classname[], szOut[], maxlen) {
    if (equal(classname, "wf_sentry")) copy(szOut, maxlen, "Турель TF2");
    else if (equal(classname, "wf_pvo")) copy(szOut, maxlen, "Радар ПВО");
    else if (equal(classname, "wf_barricade")) copy(szOut, maxlen, "Баррикада");
    else if (equal(classname, "wf_tesla")) copy(szOut, maxlen, "Вышка Тесла");
    else if (equal(classname, "wf_dispenser")) copy(szOut, maxlen, "Раздатчик");
    else if (equal(classname, "wf_generator")) copy(szOut, maxlen, "Генератор");
    else if (equal(classname, "wf_rszo")) copy(szOut, maxlen, "РСЗО «Град»");
    else if (equal(classname, "wf_emp")) copy(szOut, maxlen, "ЭМИ-Глушилка");
    else copy(szOut, maxlen, "Постройка");
}

public Task_RefreshBuildings() {
    g_iFriendlyCount[0] = 0; // T
    g_iFriendlyCount[1] = 0; // CT

    for (new c = 0; c < sizeof(g_szBuildingClasses); c++) {
        new ent = -1;
        while ((ent = engfunc(EngFunc_FindEntityByString, ent, "classname", g_szBuildingClasses[c])) != 0) {
            if (!pev_valid(ent)) continue;

            new team = pev(ent, pev_iuser2);
            if (team == 1) { // CS_TEAM_T
                if (g_iFriendlyCount[0] < sizeof(g_iFriendlyBuildings[])) {
                    g_iFriendlyBuildings[0][g_iFriendlyCount[0]++] = ent;
                }
            } else if (team == 2) { // CS_TEAM_CT
                if (g_iFriendlyCount[1] < sizeof(g_iFriendlyBuildings[])) {
                    g_iFriendlyBuildings[1][g_iFriendlyCount[1]++] = ent;
                }
            }
        }
    }
}

public client_PreThink(id) {
    if (!get_pcvar_num(g_cvarEnable) || !is_user_alive(id)) return;

    new CsTeams:team = cs_get_user_team(id);
    new t = -1;
    if (team == CS_TEAM_T) t = 0;
    else if (team == CS_TEAM_CT) t = 1;
    else return;

    // 1. Semiclip pass-through for friendly buildings
    new count = g_iFriendlyCount[t];
    new Float:p_orig[3];
    pev(id, pev_origin, p_orig);
    new flags = pev(id, pev_flags);
    new Float:feet_z = p_orig[2] - ((flags & FL_DUCKING) ? 18.0 : 36.0);

    for (new i = 0; i < count; i++) {
        new ent = g_iFriendlyBuildings[t][i];
        if (!pev_valid(ent)) continue;

        new Float:b_orig[3], Float:b_maxs[3];
        pev(ent, pev_origin, b_orig);
        pev(ent, pev_maxs, b_maxs);
        new Float:top_z = b_orig[2] + b_maxs[2];

        // If player is walking / at body level: make non-solid so they pass smoothly through!
        // If player is standing/landing on top of the structure: keep solid so they can stand on top!
        if (feet_z < (top_z - 4.0)) {
            set_pev(ent, pev_solid, SOLID_NOT);
        }
    }

    // 2. Field Repair & HUD info when looking at friendly building
    new buttons = pev(id, pev_button);
    new aim_target, aim_body;
    get_user_aiming(id, aim_target, aim_body, 140);
    if (aim_target > 0 && pev_valid(aim_target)) {
        new s_team = pev(aim_target, pev_iuser2);
        if (s_team == t + 1) { // Matches player team
            new cname[32];
            pev(aim_target, pev_classname, cname, charsmax(cname));
            if (cname[0] == 'w' && cname[1] == 'f' && cname[2] == '_') {
                new Float:hp, Float:maxhp;
                pev(aim_target, pev_health, hp);
                pev(aim_target, pev_max_health, maxhp);
                if (maxhp <= 0.0) maxhp = 1000.0;

                new Float:curtime = get_gametime();
                if (curtime >= g_flLastRepairHUD[id]) {
                    g_flLastRepairHUD[id] = curtime + 0.2;
                    new szName[32];
                    GetBuildingNiceName(cname, szName, charsmax(szName));

                    set_hudmessage(0, 220, 255, -1.0, 0.68, 0, 0.0, 0.25, 0.05, 0.05, -1);
                    if (hp < maxhp) {
                        show_hudmessage(id, "[СОЮЗНАЯ ПОСТРОЙКА: %s]^nПрочность: %.0f / %.0f HP^n[Удерживайте E для ремонта (-$25 / +50 HP)]", szName, hp, maxhp);
                    } else {
                        show_hudmessage(id, "[СОЮЗНАЯ ПОСТРОЙКА: %s]^nПрочность: %.0f / %.0f HP [100%% - ИСПРАВНА]", szName, hp, maxhp);
                    }
                }

                // REPAIR ACTION ON [E]
                if ((buttons & IN_USE) && hp < maxhp && curtime >= g_flNextRepairTime[id]) {
                    g_flNextRepairTime[id] = curtime + 0.35;
                    new money = cs_get_user_money(id);
                    if (money >= 25) {
                        cs_set_user_money(id, money - 25);
                        hp = floatmin(maxhp, hp + 50.0);
                        set_pev(aim_target, pev_health, hp);
                        emit_sound(aim_target, CHAN_ITEM, "weapons/knife_hitwall1.wav", 0.8, ATTN_NORM, 0, 115);

                        new Float:t_orig[3];
                        pev(aim_target, pev_origin, t_orig);
                        message_begin(MSG_BROADCAST, SVC_TEMPENTITY);
                        write_byte(TE_SPARKS);
                        write_coord(floatround(t_orig[0]));
                        write_coord(floatround(t_orig[1]));
                        write_coord(floatround(t_orig[2] + 20.0));
                        message_end();
                    } else {
                        client_print(id, print_center, "[!] Недостаточно средств ($25) для полевого ремонта!");
                    }
                }
            }
        }
    }
}

public client_PostThink(id) {
    if (!get_pcvar_num(g_cvarEnable) || !is_user_alive(id)) return;

    new CsTeams:team = cs_get_user_team(id);
    new t = -1;
    if (team == CS_TEAM_T) t = 0;
    else if (team == CS_TEAM_CT) t = 1;
    else return;

    new count = g_iFriendlyCount[t];
    if (count == 0) return;

    for (new i = 0; i < count; i++) {
        new ent = g_iFriendlyBuildings[t][i];
        if (pev_valid(ent)) {
            set_pev(ent, pev_solid, SOLID_BBOX);
        }
    }
}
