0%
Обязательно ознакомьтесь с правилами форума!
Требуются люди в Команду форума для наполнения сайта ресурсами и полезным контентом. Писать в Telegram: @g_r_e_a_t_z_a_r_a_z_a
Revive Teammates [Modular]

CS 1.6 Amxx Revive Teammates [Modular] 2.3.17

Модульный плагин воскрешения/минирования игроков
Код:
#include <amxmodx>
#include <hamsandwich>
#include <reapi>
#include <rt_api>

public stock const PLUGIN[] = "Revive Teammates: Bonus";
public stock const CFG_FILE[] = "addons/amxmodx/configs/rt_configs/rt_bonus.cfg";

#define MAX_SPAWN_WEAPONS 6

enum CVARS {
    WEAPONS[MAX_FMT_LENGTH],
    WEAPONS_MAPS[MAX_FMT_LENGTH],
    Float:REVIVE_HEALTH,
    Float:PLANTING_HEALTH,
    Float:HEALTH,
    ARMOR_TYPE,
    ARMOR,
    FRAGS,
    NO_DEATHPOINT
};

new g_eCvars[CVARS];

new g_iWeapons;
new g_szWeapon[MAX_SPAWN_WEAPONS][32];

public plugin_precache() {
    CreateCvars();

    server_cmd("exec %s", CFG_FILE);
    server_exec();
}

public plugin_init() {
    register_plugin(PLUGIN, VERSION, AUTHORS);
  
    register_dictionary("rt_library.txt");
}

public plugin_cfg() {
    new szMapName[MAX_MAPNAME_LENGTH], szWeapon[32];
    get_mapname(szMapName, charsmax(szMapName));
  
    if(g_eCvars[WEAPONS_MAPS][0] != EOS && containi(szMapName, "awp_") != -1) {
        while(argbreak(g_eCvars[WEAPONS_MAPS], szWeapon, charsmax(szWeapon), g_eCvars[WEAPONS_MAPS], charsmax(g_eCvars[WEAPONS_MAPS])) != -1) {
            if(g_iWeapons == MAX_SPAWN_WEAPONS)
                break;

            copy(g_szWeapon[g_iWeapons++], charsmax(g_szWeapon[]), szWeapon);
        }

        return;
    }

    if(g_eCvars[WEAPONS][0] != EOS) {
        while(argbreak(g_eCvars[WEAPONS], szWeapon, charsmax(szWeapon), g_eCvars[WEAPONS], charsmax(g_eCvars[WEAPONS])) != -1) {
            if(g_iWeapons == MAX_SPAWN_WEAPONS)
                break;

            copy(g_szWeapon[g_iWeapons++], charsmax(g_szWeapon[]), szWeapon);
        }
    }
}

public rt_revive_end(const iEnt, const iPlayer, const iActivator, const Modes:eMode) {
    switch(eMode) {
        case MODE_REVIVE: {
            new Modes:iMode = Modes:get_entvar(iEnt, var_iuser3);

            if(iMode != MODE_PLANT) {
                if(g_eCvars[REVIVE_HEALTH])
                    rg_add_health_to_player(iActivator, g_eCvars[REVIVE_HEALTH]);

                if(g_eCvars[HEALTH])
                    set_entvar(iPlayer, var_health, floatclamp(g_eCvars[HEALTH], 1.0, Float:get_entvar(iPlayer, var_max_health)));

                if(g_eCvars[ARMOR])
                    rg_set_user_armor(iPlayer, g_eCvars[ARMOR], ArmorType:g_eCvars[ARMOR_TYPE]);

                if(g_iWeapons > 0) {
                    rg_remove_all_items(iPlayer);

                    for(new i; i <= g_iWeapons; i++) {
                        new iWeapon = rg_give_item(iPlayer, g_szWeapon[i]);

                        if(!is_nullent(iWeapon)) {
                            new WeaponIdType:iWeaponType = WeaponIdType:get_member(iWeapon, m_iId);

                            if(iWeaponType != WEAPON_KNIFE && iWeaponType != WEAPON_SHIELDGUN)
                                rg_set_user_bpammo(iPlayer, iWeaponType, rg_get_iteminfo(iWeapon, ItemInfo_iMaxAmmo1));
                        }
                    }
                }

                if(g_eCvars[FRAGS])
                    ExecuteHamB(Ham_AddPoints, iActivator, g_eCvars[FRAGS], false);
              
                if(g_eCvars[NO_DEATHPOINT])
                    set_member(iPlayer, m_iDeaths, max(get_member(iPlayer, m_iDeaths) - 1, 0));
            }
        }
        case MODE_PLANT: {
            if(g_eCvars[PLANTING_HEALTH])
                rg_add_health_to_player(iActivator, g_eCvars[PLANTING_HEALTH]);
        }
    }
}

stock rg_add_health_to_player(const iPlayer, const Float:flHealth) {
    set_entvar(iPlayer, var_health, floatclamp(Float:get_entvar(iPlayer, var_health) + flHealth, 1.0, Float:get_entvar(iPlayer, var_max_health)));
}

public CreateCvars() {
    bind_pcvar_string(create_cvar(
        "rt_weapons",
        "weapon_knife weapon_deagle",
        FCVAR_NONE,
        "What weapons should be given to the player after resurrection(no more than 6)(otherwise standard from game.cfg)"),
        g_eCvars[WEAPONS],
        charsmax(g_eCvars[WEAPONS])
    );
    bind_pcvar_string(create_cvar(
        "rt_weapons_maps",
        "weapon_knife weapon_awp",
        FCVAR_NONE,
        "What weapons should be given to the player after resurrection on 'awp_' maps(no more than 6)(otherwise standard from game.cfg)"),
        g_eCvars[WEAPONS_MAPS],
        charsmax(g_eCvars[WEAPONS_MAPS])
    );
    bind_pcvar_float(create_cvar(
        "rt_revive_health",
        "0.0",
        FCVAR_NONE,
        "How much more health to add after resurrection",
        true,
        0.0),
        g_eCvars[REVIVE_HEALTH]
    );
    bind_pcvar_float(create_cvar(
        "rt_planting_health",
        "0.0",
        FCVAR_NONE,
        "How much more health to add after planting",
        true,
        0.0),
        g_eCvars[PLANTING_HEALTH]
    );
    bind_pcvar_float(create_cvar(
        "rt_health",
        "100.0",
        FCVAR_NONE,
        "The number of health of the resurrected player",
        true,
        1.0),
        g_eCvars[HEALTH]
    );
    bind_pcvar_num(create_cvar(
        "rt_armor_type",
        "2",
        FCVAR_NONE,
        "0 - do not issue armor, 1 - bulletproof vest, 2 - bulletproof vest with helmet",
        true,
        0.0,
        true,
        2.0),
        g_eCvars[ARMOR_TYPE]
    );
    bind_pcvar_num(create_cvar(
        "rt_armor",
        "100",
        FCVAR_NONE,
        "Number of armor of the resurrected player",
        true,
        0.0),
        g_eCvars[ARMOR]
    );
    bind_pcvar_num(create_cvar(
        "rt_frags",
        "1",
        FCVAR_NONE,
        "Number of frags for resurrection",
        true,
        0.0),
        g_eCvars[FRAGS]
    );
    bind_pcvar_num(create_cvar(
        "rt_restore_death",
        "0",
        FCVAR_NONE,
        "Remove the death point of a dead player after resurrection",
        true,
        0.0,
        true,
        1.0),
        g_eCvars[NO_DEATHPOINT]
    );
}
Код:
#include <amxmodx>
#include <fakemeta>
#include <hamsandwich>
#include <reapi>
#include <rt_api>

public stock const PLUGIN[] = "Revive Teammates: Core";
public stock const CFG_FILE[] = "addons/amxmodx/configs/rt_configs/rt_core.cfg";

// Custom Player Models https://dev-cs.ru/resources/928/
native bool:custom_player_models_get_path(const player, path[] = "", length = 0);
native bool:custom_player_models_get_body(const player, const any:team, &body);
native bool:custom_player_models_get_skin(const player, const any:team, &skin);

enum CVARS {
    Float:REVIVE_TIME,
    Float:ANTIFLOOD_TIME,
    Float:CORPSE_TIME,
    Float:SEARCH_RADIUS,
    FORCE_FWD_MODE
};

new g_eCvars[CVARS];

enum Forwards {
    ReviveStart,
    ReviveStart_Post,
    ReviveLoop_Pre,
    ReviveLoop_Post,
    ReviveEnd,
    ReviveCancelled,
    CreatingCorpseStart,
    CreatingCorpseEnd
};

new g_eForwards[Forwards];

new g_iPlantingPluginID;

new Float:g_fLastUse[MAX_PLAYERS + 1], g_iTimeUntil[MAX_PLAYERS + 1];

new Float:g_fVecSpawnOrigin[3];
new HookChain:g_pHook_GetPlayerSpawnSpot;
new g_szModel[MAX_PLAYERS + 1][64];
new Modes:g_iCurrentMode[MAX_PLAYERS + 1] = { MODE_NONE, ... };

public plugin_precache() {
    CreateCvars();

    server_cmd("exec %s", CFG_FILE);
    server_exec();
}

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

    register_dictionary("rt_library.txt");

    register_message(get_user_msgid("ClCorpse"), "MessageHook_ClCorpse");

    RegisterHookChain(RG_CSGameRules_CleanUpMap, "CSGameRules_CleanUpMap_Post", true);
    RegisterHookChain(RG_CBasePlayer_UseEmpty, "CBasePlayer_UseEmpty_Pre", false);
    DisableHookChain((g_pHook_GetPlayerSpawnSpot = RegisterHookChain(RG_CSGameRules_GetPlayerSpawnSpot, "CSGameRules_GetPlayerSpawnSpot_Pre", false)));
    RegisterHookChain(RG_CBasePlayer_Spawn, "CBasePlayer_Spawn_Pre", false);
    RegisterHookChain(RG_CBasePlayer_SetClientUserInfoModel, "CBasePlayer_SetClientUserInfoModel_Pre");

    g_eForwards[ReviveStart] = CreateMultiForward("rt_revive_start", ET_STOP, FP_CELL, FP_CELL, FP_CELL, FP_CELL);
    g_eForwards[ReviveStart_Post] = CreateMultiForward("rt_revive_start_post", ET_IGNORE, FP_CELL, FP_CELL, FP_CELL, FP_CELL);
    g_eForwards[ReviveLoop_Pre] = CreateMultiForward("rt_revive_loop_pre", ET_STOP, FP_CELL, FP_CELL, FP_CELL, FP_FLOAT, FP_CELL);
    g_eForwards[ReviveLoop_Post] = CreateMultiForward("rt_revive_loop_post", ET_IGNORE, FP_CELL, FP_CELL, FP_CELL, FP_FLOAT, FP_CELL);
    g_eForwards[ReviveEnd] = CreateMultiForward("rt_revive_end", ET_IGNORE, FP_CELL, FP_CELL, FP_CELL, FP_CELL);
    g_eForwards[ReviveCancelled] = CreateMultiForward("rt_revive_cancelled", ET_IGNORE, FP_CELL, FP_CELL, FP_CELL, FP_CELL);
    g_eForwards[CreatingCorpseStart] = CreateMultiForward("rt_creating_corpse_start", ET_STOP, FP_CELL, FP_CELL);
    g_eForwards[CreatingCorpseEnd] = CreateMultiForward("rt_creating_corpse_end", ET_IGNORE, FP_CELL, FP_CELL, FP_ARRAY);

    g_iPlantingPluginID = is_plugin_loaded("rt_planting.amxx", true);
}

public client_disconnected(iPlayer) {
    g_fLastUse[iPlayer] = 0.0;

    PlayerSpawnOrDisconnect(iPlayer);
}

public client_remove(iPlayer) {
    g_iCurrentMode[iPlayer] = MODE_NONE;
}

public CSGameRules_CleanUpMap_Post() {
    arrayset(g_iCurrentMode, MODE_NONE, sizeof(g_iCurrentMode));
    RemoveCorpses(0, DEAD_BODY_CLASSNAME);
}

public CBasePlayer_UseEmpty_Pre(const iActivator) {
    if(~get_entvar(iActivator, var_flags) & FL_ONGROUND)
        return;

    new iEnt = RT_NULLENT;

    new Float:fVecPlOrigin[3], Float:fVecEntOrigin[3];
    get_entvar(iActivator, var_origin, fVecPlOrigin);

    while((iEnt = rg_find_ent_by_class(iEnt, DEAD_BODY_CLASSNAME)) > 0) {
        if(!is_nullent(iEnt)) {
            get_entvar(iEnt, var_vuser4, fVecEntOrigin);

            if(ExecuteHam(Ham_FVecInViewCone, iActivator, fVecEntOrigin) && vector_distance(fVecPlOrigin, fVecEntOrigin) < g_eCvars[SEARCH_RADIUS]) {
                Corpse_Use(iEnt, iActivator);
                return;
            }
        }
    }
}

public CSGameRules_GetPlayerSpawnSpot_Pre(const iPlayer) {
    DisableHookChain(g_pHook_GetPlayerSpawnSpot);

    set_entvar(iPlayer, var_flags, get_entvar(iPlayer, var_flags) | FL_DUCKING);

    set_entvar(iPlayer, var_velocity, NULL_VECTOR);
    set_entvar(iPlayer, var_v_angle, NULL_VECTOR);

    new Float:fVecAngles[3];
    get_entvar(iPlayer, var_angles, fVecAngles);
    fVecAngles[0] = fVecAngles[2] = 0.0;
    set_entvar(iPlayer, var_angles, fVecAngles);

    set_entvar(iPlayer, var_punchangle, NULL_VECTOR);
    set_entvar(iPlayer, var_fixangle, 1);

    engfunc(EngFunc_SetSize, iPlayer, Float:{-16.000000, -16.000000, -18.000000}, Float:{16.000000, 16.000000, 32.000000});
    engfunc(EngFunc_SetOrigin, iPlayer, g_fVecSpawnOrigin);

    SetHookChainReturn(ATYPE_INTEGER, RT_NULLENT);
    return HC_SUPERCEDE;
}

public CBasePlayer_Spawn_Pre(const iPlayer) {
    PlayerSpawnOrDisconnect(iPlayer);
}

public CBasePlayer_SetClientUserInfoModel_Pre(const iPlayer, szInfoBuffer[], szNewModel[]) {
    copy(g_szModel[iPlayer], charsmax(g_szModel[]), szNewModel);
}

public Corpse_Use(const iEnt, const iActivator) {
    if(is_nullent(iEnt) || get_member_game(m_bRoundTerminating) || !ExecuteHam(Ham_IsPlayer, iActivator))
        return;

    new iPlayer = get_entvar(iEnt, var_owner);
    new TeamName:iPlTeam = TeamName:get_member(iPlayer, m_iTeam);
    new TeamName:iActTeam = TeamName:get_member(iActivator, m_iTeam);
    new TeamName:iEntTeam = TeamName:get_entvar(iEnt, var_team);
    new Modes:eCurrentMode = (iActTeam == iPlTeam) ? MODE_REVIVE : MODE_PLANT;

    if(g_iPlantingPluginID == INVALID_PLUGIN_ID && eCurrentMode == MODE_PLANT)
        return;

    if(iActTeam == TEAM_SPECTATOR || iPlTeam == TEAM_SPECTATOR)
        return;

    if(iEntTeam != iPlTeam) {
        NotifyClient(iActivator, print_team_red, "RT_CHANGE_TEAM");
        return;
    }

    if(get_entvar(iEnt, var_iuser1)) {
        NotifyClient(iActivator, print_team_red, "RT_ACTIVATOR_EXISTS");
        return;
    }

    if(!is_user_alive(iActivator)) {
        ResetCorpseThink(g_eForwards[ReviveCancelled], iEnt, iPlayer, iActivator, eCurrentMode);
        return;
    }

    new fwRet;
    ExecuteForward(g_eForwards[ReviveStart], fwRet, iEnt, iPlayer, iActivator, eCurrentMode);

    if(fwRet == PLUGIN_HANDLED) {
        ResetCorpseThink(g_eForwards[ReviveCancelled], iEnt, iPlayer, iActivator, eCurrentMode);
        return;
    }

    new Float:fGameTime = get_gametime();

    if(g_fLastUse[iActivator] > fGameTime) {
        NotifyClient(iActivator, print_team_red, "RT_ANTI_FLOOD");
        ResetCorpseThink(g_eForwards[ReviveCancelled], iEnt, iPlayer, iActivator, eCurrentMode);
        return;
    }

    g_fLastUse[iActivator] = fGameTime + g_eCvars[ANTIFLOOD_TIME];

    NotifyClient(iActivator, print_team_blue, eCurrentMode == MODE_REVIVE ? "RT_TIMER_REVIVE" : "RT_TIMER_PLANT", iPlayer);

    g_iTimeUntil[iActivator] = 0;

    set_entvar(iEnt, var_iuser1, iActivator);
    set_entvar(iEnt, var_iuser2, eCurrentMode);
    set_entvar(iEnt, var_fuser1, fGameTime + g_eCvars[REVIVE_TIME]);
    set_entvar(iEnt, var_fuser3, g_eCvars[REVIVE_TIME]);
    set_entvar(iEnt, var_nextthink, fGameTime + 0.1);

    g_iCurrentMode[iActivator] = eCurrentMode;

    ExecuteForward(g_eForwards[ReviveStart_Post], _, iEnt, iPlayer, iActivator, eCurrentMode);
}

public Corpse_Think(const iEnt) {
    if(is_nullent(iEnt))
        return;

    new iPlayer = get_entvar(iEnt, var_owner);
    new iActivator = get_entvar(iEnt, var_iuser1);
    new Float:fGameTime = get_gametime();

    if(!iActivator) {
        if(g_eCvars[CORPSE_TIME] && Float:get_entvar(iEnt, var_fuser4) < fGameTime) {
            RemoveCorpses(iPlayer, DEAD_BODY_CLASSNAME);
            return;
        }

        set_entvar(iEnt, var_nextthink, fGameTime + 1.0);
        return;
    }

    new TeamName:iPlTeam = TeamName:get_member(iPlayer, m_iTeam);
    new TeamName:iEntTeam = TeamName:get_entvar(iEnt, var_team);
    new Modes:eCurrentMode = Modes:get_entvar(iEnt, var_iuser2);

    if(iEntTeam != iPlTeam) {
        NotifyClient(iActivator, print_team_red, "RT_CHANGE_TEAM");
        ResetCorpseThink(g_eForwards[ReviveCancelled], iEnt, iPlayer, iActivator, eCurrentMode);
        return;
    }

    if(~get_entvar(iActivator, var_button) & IN_USE) {
        NotifyClient(iActivator, print_team_red, eCurrentMode == MODE_REVIVE ? "RT_CANCELLED_REVIVE" : "RT_CANCELLED_PLANT");
        ResetCorpseThink(g_eForwards[ReviveCancelled], iEnt, iPlayer, iActivator, eCurrentMode);
        return;
    }

    new Float:fTimeUntil[2];
    fTimeUntil[0] = Float:get_entvar(iEnt, var_fuser1);
    fTimeUntil[1] = Float:get_entvar(iEnt, var_fuser3);

    g_iTimeUntil[iActivator]++;

    if(g_iTimeUntil[iActivator] == 10 || g_eCvars[FORCE_FWD_MODE]) {
        if(g_eCvars[FORCE_FWD_MODE]) {
            fTimeUntil[1] -= 0.1;
        }
        else {
            fTimeUntil[1] -= 1.0;
        }

        if(!is_user_alive(iActivator)) {
            ResetCorpseThink(g_eForwards[ReviveCancelled], iEnt, iPlayer, iActivator, eCurrentMode);
            return;
        }

        new fwRet;
        ExecuteForward(g_eForwards[ReviveLoop_Pre], fwRet, iEnt, iPlayer, iActivator, fTimeUntil[1], eCurrentMode);

        if(fwRet == PLUGIN_HANDLED) {
            ResetCorpseThink(g_eForwards[ReviveCancelled], iEnt, iPlayer, iActivator, eCurrentMode);
            return;
        }
    }

    if(fGameTime > fTimeUntil[0]) {
        new Modes:iMode = Modes:get_entvar(iEnt, var_iuser3);

        if(eCurrentMode == MODE_REVIVE && iMode != MODE_PLANT) {
            NotifyClient(iActivator, print_team_red, "RT_REVIVE", iPlayer);
            NotifyClient(iPlayer, print_team_red, "RT_REVIVED", iActivator);

            get_entvar(iActivator, var_origin, g_fVecSpawnOrigin);

            RemoveCorpses(iPlayer, DEAD_BODY_CLASSNAME);

            EnableHookChain(g_pHook_GetPlayerSpawnSpot);
            rg_round_respawn(iPlayer);
            DisableHookChain(g_pHook_GetPlayerSpawnSpot);

            if(is_user_alive(iPlayer))
                engfunc(EngFunc_SetOrigin, iPlayer, g_fVecSpawnOrigin);
        }

        if(!is_user_alive(iActivator)) {
            ResetCorpseThink(g_eForwards[ReviveCancelled], iEnt, iPlayer, iActivator, eCurrentMode);
            return;
        }

        g_iCurrentMode[iActivator] = MODE_NONE;

        ExecuteForward(g_eForwards[ReviveEnd], _, iEnt, iPlayer, iActivator, eCurrentMode);

        return;
    }

    if(g_iTimeUntil[iActivator] == 10 || g_eCvars[FORCE_FWD_MODE]) {
        if(!is_user_alive(iActivator)) {
            ResetCorpseThink(g_eForwards[ReviveCancelled], iEnt, iPlayer, iActivator, eCurrentMode);
            return;
        }

        ExecuteForward(g_eForwards[ReviveLoop_Post], _, iEnt, iPlayer, iActivator, fTimeUntil[1], eCurrentMode);

        g_iTimeUntil[iActivator] = 0;
    }

    set_entvar(iEnt, var_fuser3, fTimeUntil[1]);
    set_entvar(iEnt, var_nextthink, fGameTime + 0.1);
}

public MessageHook_ClCorpse() {
    if(get_member_game(m_bRoundTerminating))
        return PLUGIN_HANDLED;

    enum {
        arg_body = 10,
        arg_id = 12
    };

    new iPlayer = get_msg_arg_int(arg_id);
    new TeamName:iPlTeam = TeamName:get_member(iPlayer, m_iTeam);

    if(iPlTeam == TEAM_SPECTATOR || g_szModel[iPlayer][0] == EOS)
        return PLUGIN_HANDLED;

    new iEnt = rg_create_entity("info_target");

    new fwRet;
    ExecuteForward(g_eForwards[CreatingCorpseStart], fwRet, iEnt, iPlayer);

    if(fwRet == PLUGIN_HANDLED) {
        set_entvar(iEnt, var_flags, FL_KILLME);
        set_entvar(iEnt, var_nextthink, 0.0);
        return PLUGIN_HANDLED;
    }

    /*new szModel[32], szModelPath[MAX_RESOURCE_PATH_LENGTH];
    get_user_info(iPlayer, "model", szModel, charsmax(szModel));
    formatex(szModelPath, charsmax(szModelPath), "models/player/%s/%s.mdl", szModel, szModel);*/
    new szModelPath[MAX_RESOURCE_PATH_LENGTH];

    if(!custom_player_models_get_path(iPlayer, szModelPath, charsmax(szModelPath))) {
        formatex(szModelPath, charsmax(szModelPath), "models/player/%s/%s.mdl", g_szModel[iPlayer], g_szModel[iPlayer]);
        set_entvar(iEnt, var_body, get_msg_arg_int(arg_body));
        set_entvar(iEnt, var_skin, get_entvar(iPlayer, var_skin));
    }
    else {
        new iBody, iSkin;
        custom_player_models_get_body(iPlayer, iPlTeam, iBody);
        custom_player_models_get_skin(iPlayer, iPlTeam, iSkin);
        set_entvar(iEnt, var_body, iBody);
        set_entvar(iEnt, var_skin, iSkin);
    }

    set_entvar(iEnt, var_modelindex, engfunc(EngFunc_ModelIndex, szModelPath));
    set_entvar(iEnt, var_model, szModelPath);
    //set_entvar(iEnt, var_renderfx, kRenderFxDeadPlayer);
    //set_entvar(iEnt, var_renderamt, float(iPlayer));

    set_entvar(iEnt, var_classname, DEAD_BODY_CLASSNAME);
    set_entvar(iEnt, var_sequence, get_entvar(iPlayer, var_sequence));
    set_entvar(iEnt, var_frame, 255.0);
    set_entvar(iEnt, var_owner, iPlayer);
    set_entvar(iEnt, var_team, iPlTeam);

    new Float:fVecOrigin[3];
    fVecOrigin[0] = float(get_msg_arg_int(2) / 128);
    fVecOrigin[1] = float(get_msg_arg_int(3) / 128);
    fVecOrigin[2] = float(get_msg_arg_int(4) / 128);
    //get_entvar(iPlayer, var_origin, fVecOrigin);
    engfunc(EngFunc_SetOrigin, iEnt, fVecOrigin);

    new Float:fVecAngles[3];
    get_entvar(iPlayer, var_angles, fVecAngles);
    set_entvar(iEnt, var_angles, fVecAngles);

    engfunc(EngFunc_GetBonePosition, iEnt, 2, fVecOrigin, fVecAngles);
    set_entvar(iEnt, var_vuser4, fVecOrigin);

    set_entvar(iEnt, var_fuser2, g_eCvars[SEARCH_RADIUS]);

    set_entvar(iEnt, var_nextthink, get_gametime() + 1.0);
    SetThink(iEnt, "Corpse_Think");

    if(g_eCvars[CORPSE_TIME])
        set_entvar(iEnt, var_fuser4, get_gametime() + g_eCvars[CORPSE_TIME]);

    fVecOrigin[2] += 20.0;

    ExecuteForward(g_eForwards[CreatingCorpseEnd], _, iEnt, iPlayer, PrepareArray(_:fVecOrigin, sizeof(fVecOrigin)));

    return PLUGIN_HANDLED;
}

stock PlayerSpawnOrDisconnect(const iPlayer) {
    new iActivator = RemoveCorpses(iPlayer, DEAD_BODY_CLASSNAME);

    if(is_user_connected(iActivator))
        NotifyClient(iActivator, print_team_red, "RT_DISCONNECTED");

    ResetCorpseThink(g_eForwards[ReviveCancelled], RT_NULLENT, iPlayer, iActivator, MODE_NONE);

    // TODO need to handle corpse user respawn
    //if(g_iCurrentMode[iPlayer]) { }
}

public CreateCvars() {
    bind_pcvar_float(create_cvar(
        "rt_revive_time",
        "3.0",
        FCVAR_NONE,
        "Duration of the player's resurrection(in seconds)",
        true,
        1.0),
        g_eCvars[REVIVE_TIME]
    );
    bind_pcvar_float(create_cvar(
        "rt_revive_antiflood",
        "3.0",
        FCVAR_NONE,
        "Duration of anti-flood resurrection(in seconds)",
        true,
        1.0),
        g_eCvars[ANTIFLOOD_TIME]
    );
    bind_pcvar_float(create_cvar(
        "rt_corpse_time",
        "30.0",
        FCVAR_NONE,
        "Duration of a corpse's life (in seconds). If you set it to 0, the corpse lives until the end of the round.",
        true,
        0.0),
        g_eCvars[CORPSE_TIME]
    );
    bind_pcvar_float(create_cvar(
        "rt_search_radius",
        "64.0",
        FCVAR_NONE,
        "Search radius for a corpse",
        true,
        1.0),
        g_eCvars[SEARCH_RADIUS]
    );
    bind_pcvar_num(create_cvar(
        "rt_force_fwd_mode",
        "0",
        FCVAR_NONE,
        "Execute forwards more often. Set this to 1 if 'rt_no_move 1' didn't work properly.",
        true,
        0.0,
        true,
        1.0),
        g_eCvars[FORCE_FWD_MODE]
    );
}

/**
* Reset entity think
*
* @param eForward       Forward type
* @param iEnt           Corpse entity index
* @param iPlayer        Player id whose corpse
* @param iActivator     Player id who ressurect
* @param eMode          MODE_REVIVE - stopped the resurrection, MODE_PLANT - stopped planting
*
* @noreturn
*/
ResetCorpseThink(const eForward, const iEnt, iPlayer, iActivator, const Modes:eMode) {
    if(!is_nullent(iEnt)) {
        set_entvar(iEnt, var_nextthink, get_gametime() + 1.0);
        set_entvar(iEnt, var_iuser1, 0);
    }

    if(iActivator != RT_NULLENT) {
        g_iCurrentMode[iActivator] = MODE_NONE;
    }

    iPlayer = is_user_connected(iPlayer) ? iPlayer : RT_NULLENT;
    iActivator = is_user_connected(iActivator) ? iActivator : RT_NULLENT;

    ExecuteForward(eForward, _, iEnt, iPlayer, iActivator, eMode);
}

public plugin_natives() {
    set_native_filter("native_filter");
    register_native("rt_get_user_mode", "_rt_get_user_mode");
    register_native("rt_reset_use", "_rt_reset_use");
}

public Modes:_rt_get_user_mode() {
    enum { arg_user = 1 };

    return g_iCurrentMode[ get_param(arg_user) ];
}

public bool:_rt_reset_use() {
    enum { arg_user = 1 };

    new pPlayer = get_param(arg_user);

    if(g_iCurrentMode[pPlayer] == MODE_NONE) {
        return false;
    }

    new iEnt = RT_NULLENT;

    while((iEnt = rg_find_ent_by_class(iEnt, DEAD_BODY_CLASSNAME)) > 0) {
        if(!is_entity(iEnt)) {
            continue;
        }

        if(pPlayer == get_entvar(iEnt, var_iuser1)) {
            ResetCorpseThink(g_eForwards[ReviveCancelled], iEnt, get_entvar(iEnt, var_owner), pPlayer, get_entvar(iEnt, var_iuser2));
            return true;
        }
    }

    g_iCurrentMode[pPlayer] = MODE_NONE;
    return false;
}

public native_filter(const szNativeName[], iNativeID, iTrapMode) {
    return PLUGIN_HANDLED;
}
Код:
#include <amxmodx>
#include <fakemeta>
#include <reapi>
#include <rt_api>

public stock const PLUGIN[] = "Revive Teammates: Effects";
public stock const CFG_FILE[] = "addons/amxmodx/configs/rt_configs/rt_effects.cfg";

new const CORPSE_SPRITE_CLASSNAME[] = "rt_corpse_sprite";

enum CVARS {
    SPECTATOR,
    NOTIFY_DHUD,
    REVIVE_COLORS[MAX_COLORS_LENGTH],
    REVIVE_COORDS[MAX_COORDS_LENGTH],
    PLANTING_COLORS[MAX_COLORS_LENGTH],
    PLANTING_COORDS[MAX_COORDS_LENGTH],
    CORPSE_SPRITE[MAX_RESOURCE_PATH_LENGTH],
    Float:SPRITE_SCALE,
    REVIVE_GLOW[32],
    PLANTING_GLOW[32]
};

new g_eCvars[CVARS];

enum DHudData {
    COLOR_R,
    COLOR_G,
    COLOR_B,
    Float:COORD_X,
    Float:COORD_Y
};

enum GlowColors
{
    Float:REVIVE_COLOR,
    Float:PLANTING_COLOR
};
new Float:g_eGlowColors[GlowColors][3];

new g_eDHudData[Modes][DHudData];

new Float:g_fTime;

public plugin_precache() {
    CreateCvars();

    server_cmd("exec %s", CFG_FILE);
    server_exec();

    if(g_eCvars[CORPSE_SPRITE][0] != EOS)
        precache_model(g_eCvars[CORPSE_SPRITE]);

    new szHudColors[3][4];

    if(parse(g_eCvars[REVIVE_COLORS], szHudColors[0], charsmax(szHudColors[]),
    szHudColors[1], charsmax(szHudColors[]), szHudColors[2], charsmax(szHudColors[])) == 3) {
        g_eDHudData[MODE_REVIVE][COLOR_R] = str_to_num(szHudColors[0]);
        g_eDHudData[MODE_REVIVE][COLOR_G] = str_to_num(szHudColors[1]);
        g_eDHudData[MODE_REVIVE][COLOR_B] = str_to_num(szHudColors[2]);
    }

    if(parse(g_eCvars[PLANTING_COLORS], szHudColors[0], charsmax(szHudColors[]),
    szHudColors[1], charsmax(szHudColors[]), szHudColors[2], charsmax(szHudColors[])) == 3) {
        g_eDHudData[MODE_PLANT][COLOR_R] = str_to_num(szHudColors[0]);
        g_eDHudData[MODE_PLANT][COLOR_G] = str_to_num(szHudColors[1]);
        g_eDHudData[MODE_PLANT][COLOR_B] = str_to_num(szHudColors[2]);
    }

    new szHudCoords[2][8];

    if(parse(g_eCvars[REVIVE_COORDS], szHudCoords[0], charsmax(szHudCoords[]), szHudCoords[1], charsmax(szHudCoords[])) == 2) {
        g_eDHudData[MODE_REVIVE][COORD_X] = str_to_float(szHudCoords[0]);
        g_eDHudData[MODE_REVIVE][COORD_Y] = str_to_float(szHudCoords[1]);
    }

    if(parse(g_eCvars[PLANTING_COORDS], szHudCoords[0], charsmax(szHudCoords[]), szHudCoords[1], charsmax(szHudCoords[])) == 2) {
        g_eDHudData[MODE_PLANT][COORD_X] = str_to_float(szHudCoords[0]);
        g_eDHudData[MODE_PLANT][COORD_Y] = str_to_float(szHudCoords[1]);
    }
}

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

    register_dictionary("rt_library.txt");

    if(g_eCvars[CORPSE_SPRITE][0] != EOS)
        register_forward(FM_AddToFullPack, "AddToFullPack_Pre", false);
}

public plugin_cfg() {
    g_fTime = get_pcvar_float(get_cvar_pointer("rt_revive_time"));

    if(g_eCvars[REVIVE_GLOW][0] != EOS)
        g_eGlowColors[REVIVE_COLOR] = parseHEXColor(g_eCvars[REVIVE_GLOW]);

    if(g_eCvars[PLANTING_GLOW][0] != EOS)
        g_eGlowColors[PLANTING_COLOR] = parseHEXColor(g_eCvars[PLANTING_GLOW]);
}

public AddToFullPack_Pre(es, e, ent, host, flags, player, pSet) {
    if(player || !FClassnameIs(ent, CORPSE_SPRITE_CLASSNAME))
        return FMRES_IGNORED;

    if(TeamName:get_entvar(ent, var_team) != TeamName:get_member(host, m_iTeam)) {
        forward_return(FMV_CELL, false);
        return FMRES_SUPERCEDE;
    }

    return FMRES_IGNORED;
}

public rt_revive_start(const iEnt, const iPlayer, const iActivator, const Modes:eMode) {
    switch(eMode) {
        case MODE_REVIVE: {
            if(g_eCvars[SPECTATOR]) {
                rg_internal_cmd(iPlayer, "specmode", "4");
                set_entvar(iPlayer, var_iuser2, iActivator);
                set_member(iPlayer, m_hObserverTarget, iActivator);
                set_member(iPlayer, m_flNextObserverInput, get_gametime() + 1.25);
            }

            if(g_eCvars[NOTIFY_DHUD]) {
                DisplayDHudMessage(iActivator, eMode, "RT_DHUD_REVIVE", iPlayer);
                DisplayDHudMessage(iPlayer, eMode, "RT_DHUD_REVIVE2", iActivator);
            }

            if(g_eCvars[REVIVE_GLOW][0] != EOS)
                rg_set_rendering(iEnt, kRenderFxGlowShell, g_eGlowColors[REVIVE_COLOR], kRenderNormal, 30.0);
        }
        case MODE_PLANT: {
            if(g_eCvars[NOTIFY_DHUD])
                DisplayDHudMessage(iActivator, eMode, "RT_DHUD_PLANTING", iPlayer);

            if(g_eCvars[PLANTING_GLOW][0] != EOS)
                rg_set_rendering(iEnt, kRenderFxGlowShell, g_eGlowColors[PLANTING_COLOR], kRenderNormal, 30.0);
        }
    }
}

public rt_revive_cancelled(const iEnt, const iPlayer, const iActivator, const Modes:eMode) {
    if(g_eCvars[NOTIFY_DHUD]) {
        if(iActivator != RT_NULLENT)
            ClearDHudMessages(iActivator);

        if(iPlayer != RT_NULLENT)
            ClearDHudMessages(iPlayer);
    }

    switch(eMode)
    {
        case MODE_REVIVE:
        {
            if(g_eCvars[REVIVE_GLOW][0] != EOS)
                rg_set_rendering(iEnt);
        }
        case MODE_PLANT:
        {
            if(g_eCvars[PLANTING_GLOW][0] != EOS)
                rg_set_rendering(iEnt);
        }
    }
}

public rt_revive_end(const iEnt, const iPlayer, const iActivator, const Modes:eMode) {
    if(g_eCvars[NOTIFY_DHUD]) {
        ClearDHudMessages(iActivator);
        ClearDHudMessages(iPlayer);
    }

    switch(eMode)
    {
        case MODE_REVIVE:
        {
            static iMode;
            iMode = get_entvar(iEnt, var_iuser3);

            if(any:iMode != MODE_PLANT && g_eCvars[REVIVE_GLOW][0] != EOS)
                rg_set_rendering(iEnt);
        }
        case MODE_PLANT:
        {
            if(g_eCvars[PLANTING_GLOW][0] != EOS)
                rg_set_rendering(iEnt);
        }
    }
}

public rt_creating_corpse_end(const iEnt, const iPlayer, const Float:fVecOrigin[3]) {
    if(g_eCvars[CORPSE_SPRITE][0] == EOS)
        return;

    new iEntSprite = rg_create_entity("info_target");

    engfunc(EngFunc_SetOrigin, iEntSprite, fVecOrigin);
    engfunc(EngFunc_SetModel, iEntSprite, g_eCvars[CORPSE_SPRITE]);

    set_entvar(iEntSprite, var_classname, CORPSE_SPRITE_CLASSNAME);
    set_entvar(iEntSprite, var_owner, iPlayer);
    set_entvar(iEntSprite, var_iuser1, iEnt);
    set_entvar(iEntSprite, var_team, TeamName:get_entvar(iEnt, var_team));
    set_entvar(iEntSprite, var_scale, g_eCvars[SPRITE_SCALE]);
    set_entvar(iEntSprite, var_renderfx, kRenderFxNone);
    set_entvar(iEntSprite, var_rendercolor, Float:{255.0, 255.0, 255.0});
    set_entvar(iEntSprite, var_rendermode, kRenderTransAlpha);
    set_entvar(iEntSprite, var_renderamt, 255.0);
    set_entvar(iEntSprite, var_nextthink, get_gametime() + 0.1);

    SetThink(iEntSprite, "CorpseSprite_Think");
}

public CorpseSprite_Think(const iEnt) {
    new iHostEnt = get_entvar(iEnt, var_iuser1);

    if(is_nullent(iHostEnt) || !FClassnameIs(iHostEnt, DEAD_BODY_CLASSNAME)) {
        RemoveCorpses(get_entvar(iEnt, var_owner), CORPSE_SPRITE_CLASSNAME);
        return;
    }

    set_entvar(iEnt, var_nextthink, get_gametime() + 0.1);
}

stock rg_set_rendering(const id, const fx = kRenderFxNone, const Float:fColor[3] = {0.0, 0.0, 0.0}, const render = kRenderNormal, const Float:fAmount = 0.0)
{
    set_entvar(id, var_renderfx, fx);
    set_entvar(id, var_rendercolor, fColor);
    set_entvar(id, var_rendermode, render);
    set_entvar(id, var_renderamt, fAmount);
}

stock Float:parseHEXColor(const value[])
{
    new Float:result[3];

    if(value[0] != '#' && strlen(value) != 7)
        return result;

    result[0] = parse16bit(value[1], value[2]);
    result[1] = parse16bit(value[3], value[4]);
    result[2] = parse16bit(value[5], value[6]);

    return result;
}

stock Float:parse16bit(ch1, ch2)
{
    return float(parseHex(ch1) * 16 + parseHex(ch2));
}

stock parseHex(const ch)
{
    switch(ch)
    {
        case '0'..'9': return (ch - '0');
        case 'a'..'f': return (10 + ch - 'a');
        case 'A'..'F': return (10 + ch - 'A');
    }

    return 0;
}

stock DisplayDHudMessage(const iPlayer, const Modes:eMode, any:...) {
    new szMessage[128];
    SetGlobalTransTarget(iPlayer);
    vformat(szMessage, charsmax(szMessage), "%l", 3);

    set_dhudmessage(g_eDHudData[eMode][COLOR_R], g_eDHudData[eMode][COLOR_G], g_eDHudData[eMode][COLOR_B],
    g_eDHudData[eMode][COORD_X], g_eDHudData[eMode][COORD_Y], .holdtime = g_fTime);
    show_dhudmessage(iPlayer, szMessage);
}

stock ClearDHudMessages(const iPlayer, const iChannel = 8) {
    for(new i; i < iChannel; i++)
        show_dhudmessage(iPlayer, "");
}

public CreateCvars() {
    bind_pcvar_num(create_cvar(
        "rt_spectator",
        "1",
        FCVAR_NONE,
        "Automatically observe the resurrecting player",
        true,
        0.0,
        true,
        1.0),
        g_eCvars[SPECTATOR]
    );
    bind_pcvar_num(create_cvar(
        "rt_notify_dhud",
        "1",
        FCVAR_NONE,
        "Notification above the timer(DHUD)",
        true,
        0.0,
        true,
        1.0),
        g_eCvars[NOTIFY_DHUD]
    );
    bind_pcvar_string(create_cvar(
        "rt_revive_dhud_colors",
        "0 255 0",
        FCVAR_NONE,
        "DHUD's color at resurrection"),
        g_eCvars[REVIVE_COLORS],
        charsmax(g_eCvars[REVIVE_COLORS])
    );
    bind_pcvar_string(create_cvar(
        "rt_revive_dhud_coords",
        "-1.0 0.8",
        FCVAR_NONE,
        "DHUD's coordinates at resurrection"),
        g_eCvars[REVIVE_COORDS],
        charsmax(g_eCvars[REVIVE_COORDS])
    );
    bind_pcvar_string(create_cvar(
        "rt_planting_dhud_colors",
        "255 0 0",
        FCVAR_NONE,
        "DHUD's color at planting"),
        g_eCvars[PLANTING_COLORS],
        charsmax(g_eCvars[PLANTING_COLORS])
    );
    bind_pcvar_string(create_cvar(
        "rt_planting_dhud_coords",
        "-1.0 0.8",
        FCVAR_NONE,
        "DHUD's coordinates at planting"),
        g_eCvars[PLANTING_COORDS],
        charsmax(g_eCvars[PLANTING_COORDS])
    );
    bind_pcvar_string(create_cvar(
        "rt_corpse_sprite",
        "sprites/rt/corpse_sprite2.spr",
        FCVAR_NONE,
        "Resurrection sprite over a corpse. To disable the function, leave the cvar empty"),
        g_eCvars[CORPSE_SPRITE],
        charsmax(g_eCvars[CORPSE_SPRITE])
    );
    bind_pcvar_float(create_cvar(
        "rt_sprite_scale",
        "0.15",
        FCVAR_NONE,
        "Sprite scale",
        true,
        0.1,
        true,
        0.5),
        g_eCvars[SPRITE_SCALE]
    );
    bind_pcvar_string(create_cvar(
        "rt_revive_glow",
        "#5da130",
        FCVAR_NONE,
        "The color of the corpse being resurrected(HEX)"),
        g_eCvars[REVIVE_GLOW],
        charsmax(g_eCvars[REVIVE_GLOW])
    );
    bind_pcvar_string(create_cvar(
        "rt_planting_glow",
        "#9b2d30",
        FCVAR_NONE,
        "The color of the corpse being planted(HEX)"),
        g_eCvars[PLANTING_GLOW],
        charsmax(g_eCvars[PLANTING_GLOW])
    );
}
Код:
#include <amxmodx>
#include <hamsandwich>
#include <reapi>
#include <rt_api>

public stock const PLUGIN[] = "Revive Teammates: Planting";
public stock const CFG_FILE[] = "addons/amxmodx/configs/rt_configs/rt_planting.cfg";

enum CVARS {
    Float:DAMAGE,
    Float:RADIUS,
    MAX_PLANTING
};

new g_eCvars[CVARS];

enum _:PlayerData {
    PLANTING_COUNT
};

new g_ePlayerData[MAX_PLAYERS + 1][PlayerData];

new g_szModels[3];

public plugin_precache() {
    g_szModels[0] = precache_model("sprites/zerogxplode.spr");
    g_szModels[1] = precache_model("sprites/eexplo.spr");
    g_szModels[2] = precache_model("sprites/fexplo.spr");

    CreateCvars();

    server_cmd("exec %s", CFG_FILE);
    server_exec();
}

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

    register_dictionary("rt_library.txt");

    RegisterHookChain(RG_CSGameRules_CleanUpMap, "CSGameRules_CleanUpMap_Post", true);
}

public CSGameRules_CleanUpMap_Post() {
    arrayset(g_ePlayerData[0][_:0], 0, sizeof(g_ePlayerData) * sizeof(g_ePlayerData[]));
}

public client_disconnected(iPlayer) {
    g_ePlayerData[iPlayer][PLANTING_COUNT] = 0;
}

public rt_revive_start(const iEnt, const iPlayer, const iActivator, const Modes:eMode) {
    new Modes:iMode = Modes:get_entvar(iEnt, var_iuser3);
  
    if(eMode == MODE_PLANT) {
        if(g_ePlayerData[iActivator][PLANTING_COUNT] >= g_eCvars[MAX_PLANTING]) {
            NotifyClient(iActivator, print_team_red, "RT_PLANTING_COUNT");
            return PLUGIN_HANDLED;
        }

        if(iMode == MODE_PLANT) {
            NotifyClient(iActivator, print_team_red, "RT_IS_PLANTED", iPlayer);
            return PLUGIN_HANDLED;
        }
    }

    return PLUGIN_CONTINUE;
}

public rt_revive_end(const iEnt, const iPlayer, const iActivator, const Modes:eMode) {
    switch(eMode) {
        case MODE_REVIVE: {
            new Modes:iMode = Modes:get_entvar(iEnt, var_iuser3);

            if(iMode == MODE_PLANT) {
                new Float:fVecOrigin[3];
                get_entvar(iActivator, var_origin, fVecOrigin);
                MakeExplosionEffects(fVecOrigin);
              
                new iPlanter = get_entvar(iEnt, var_iuser4);
              
                for(new iVictim = 1, Float:fReduceDamage, Float:fVecEnd[3]; iVictim <= MaxClients; iVictim++) {
                    if(!is_user_alive(iVictim) || TeamName:get_member(iVictim, m_iTeam) != TeamName:get_member(iPlayer, m_iTeam))
                        continue;
                  
                    get_entvar(iVictim, var_origin, fVecEnd);

                    if((fReduceDamage = (g_eCvars[DAMAGE] - vector_distance(fVecOrigin, fVecEnd) * (g_eCvars[DAMAGE] / g_eCvars[RADIUS]))) < 1.0)
                        continue;
                  
                    set_member(iVictim, m_LastHitGroup, HITGROUP_GENERIC);

                    ExecuteHamB(Ham_TakeDamage, iVictim, iEnt, iPlanter, fReduceDamage, DMG_GRENADE | DMG_ALWAYSGIB);
                }

                RemoveCorpses(iPlayer, DEAD_BODY_CLASSNAME);
            }
        }
        case MODE_PLANT: {
            NotifyClient(iActivator, print_team_blue, "RT_PLANTING", iPlayer);
          
            g_ePlayerData[iActivator][PLANTING_COUNT]++;

            set_entvar(iEnt, var_iuser1, 0);
            set_entvar(iEnt, var_iuser3, eMode);
            set_entvar(iEnt, var_iuser4, iActivator);
        }
    }
}

stock MakeExplosionEffects(const Float:fVecOrigin[3]) {
    message_begin_f(MSG_PAS, SVC_TEMPENTITY, fVecOrigin);
    write_byte(TE_EXPLOSION);
    write_coord_f(fVecOrigin[0]);
    write_coord_f(fVecOrigin[1]);
    write_coord_f(fVecOrigin[2] + 20.0);
    write_short(g_szModels[2]);
    write_byte(25);
    write_byte(30);
    write_byte(TE_EXPLFLAG_NONE);
    message_end();
  
    message_begin_f(MSG_PAS, SVC_TEMPENTITY, fVecOrigin);
    write_byte(TE_EXPLOSION);
    write_coord_f(fVecOrigin[0] + random_float(-64.0, 64.0));
    write_coord_f(fVecOrigin[1] + random_float(-64.0, 64.0));
    write_coord_f(fVecOrigin[2] + random_float(30.0, 35.0));
    write_short(g_szModels[1]);
    write_byte(30);
    write_byte(30);
    write_byte(TE_EXPLFLAG_NONE);
    message_end();

    for(new i; i < 3; i++) {
        message_begin_f(MSG_PAS, SVC_TEMPENTITY, fVecOrigin);
        write_byte(TE_SPRITE);
        write_coord_f(fVecOrigin[0] + random_float(-256.0, 256.0));
        write_coord_f(fVecOrigin[1] + random_float(-256.0, 256.0));
        write_coord_f(fVecOrigin[2] + random_float(-10.0, 10.0));
        write_short(g_szModels[i]);
        write_byte(30);
        write_byte(150);
        message_end();
    }
}

public CreateCvars() {
    bind_pcvar_float(create_cvar(
        "rt_explosion_damage",
        "255.0",
        FCVAR_NONE,
        "Explosion damage",
        true,
        1.0),
        g_eCvars[DAMAGE]
    );
    bind_pcvar_float(create_cvar(
        "rt_explosion_radius",
        "200.0",
        FCVAR_NONE,
        "Explosion radius",
        true,
        1.0),
        g_eCvars[RADIUS]
    );
    bind_pcvar_num(create_cvar(
        "rt_max_planting",
        "3",
        FCVAR_NONE,
        "Maximum number of planting corpses per round",
        true,
        1.0),
        g_eCvars[MAX_PLANTING]
    );
}
Код:
#include <amxmodx>
#include <reapi>
#include <rt_api>

public stock const PLUGIN[] = "Revive Teammates: Restrictions";
public stock const CFG_FILE[] = "addons/amxmodx/configs/rt_configs/rt_restrictions.cfg";

#define m_iCurrentRound (get_member_game(m_iTotalRoundsPlayed) + 1)

enum CVARS {
    ACCESS[32],
    MAX_REVIVES,
    MAX_SPAWNS,
    NO_FIRE,
    BOMB,
    DUEL,
    SURVIVOR,
    MIN_ROUND,
    NO_MOVE,
    WIN_DIFF,
    REVIVE_COST,
    PLANTING_COST,
    Float:REMAINING_TIME,
    FORCE_FWD_MODE
};

new g_eCvars[CVARS];

enum _:PlayerData {
    REVIVE_COUNT
};

const PREVENT_FLAGS = (PLAYER_PREVENT_CLIMB|PLAYER_PREVENT_JUMP);

new g_ePlayerData[MAX_PLAYERS + 1][PlayerData];

new g_iAccessFlags;

public plugin_precache() {
    CreateCvars();

    server_cmd("exec %s", CFG_FILE);
    server_exec();
}

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

    register_dictionary("rt_library.txt");

    RegisterHookChain(RG_CSGameRules_CleanUpMap, "CSGameRules_CleanUpMap_Post", true);
}

public plugin_cfg() {
    g_iAccessFlags = read_flags(g_eCvars[ACCESS]);

    if(g_eCvars[NO_MOVE] == 1)
        RegisterHookChain(RG_CBasePlayer_PreThink, "CBasePlayer_PreThink_Pre");
}

public CSGameRules_CleanUpMap_Post() {
    arrayset(g_ePlayerData[0][_:0], 0, sizeof(g_ePlayerData) * sizeof(g_ePlayerData[]));
}

public client_disconnected(iPlayer) {
    g_ePlayerData[iPlayer][REVIVE_COUNT] = 0;
}

public CBasePlayer_PreThink_Pre(const iPlayer) {
    if(is_user_alive(iPlayer) && (get_entvar(iPlayer, var_iuser3) & PREVENT_FLAGS))
        set_entvar(iPlayer, var_maxspeed, 1.0);
}

public rt_revive_start(const iEnt, const iPlayer, const iActivator, const Modes:eMode) {
    if(~get_user_flags(iActivator) & g_iAccessFlags) {
        NotifyClient(iActivator, print_team_red, "RT_NO_ACCESS");
        return PLUGIN_HANDLED;
    }

    if(m_iCurrentRound < g_eCvars[MIN_ROUND]) {
        NotifyClient(iActivator, print_team_red, "RT_MIN_ROUND", g_eCvars[MIN_ROUND]);
        return PLUGIN_HANDLED;
    }

    if(g_eCvars[BOMB] && rg_is_bomb_planted()) {
        NotifyClient(iActivator, print_team_red, "RT_BOMB");
        return PLUGIN_HANDLED;
    }

    if(g_eCvars[DUEL] && rg_users_count(false)) {
        NotifyClient(iActivator, print_team_red, "RT_DUEL");
        return PLUGIN_HANDLED;
    }

    if(g_eCvars[SURVIVOR] && rg_users_count(true)) {
        NotifyClient(iActivator, print_team_red, "RT_SURVIVOR");
        return PLUGIN_HANDLED;
    }

    if(g_eCvars[REMAINING_TIME] && rg_get_remaining_time() <= g_eCvars[REMAINING_TIME]) {
        NotifyClient(iActivator, print_team_red, "RT_REMAINING_TIME");
        return PLUGIN_HANDLED;
    }

    if(g_eCvars[WIN_DIFF] && (rg_get_team_wins_row(g_eCvars[WIN_DIFF]) == TeamName:get_member(iActivator, m_iTeam))) {
        NotifyClient(iActivator, print_team_red, "RT_WINS_DOMINATION");
        return PLUGIN_HANDLED;
    }

    switch(eMode) {
        case MODE_REVIVE: {
            if(g_ePlayerData[iActivator][REVIVE_COUNT] >= g_eCvars[MAX_REVIVES]) {
                NotifyClient(iActivator, print_team_red, "RT_REVIVE_COUNT");
                return PLUGIN_HANDLED;
            }

            if(get_member(iPlayer, m_iNumSpawns) > g_eCvars[MAX_SPAWNS]) {
                NotifyClient(iActivator, print_team_red, "RT_MAX_SPAWNS");
                return PLUGIN_HANDLED;
            }

            if(get_member(iActivator, m_iAccount) < g_eCvars[REVIVE_COST]) {
                NotifyClient(iActivator, print_team_red, "RT_NO_MONEY");
                return PLUGIN_HANDLED;
            }
        }
        case MODE_PLANT: {
            if(get_member(iActivator, m_iAccount) < g_eCvars[PLANTING_COST]) {
                NotifyClient(iActivator, print_team_red, "RT_NO_MONEY");
                return PLUGIN_HANDLED;
            }
        }
    }

    if(g_eCvars[NO_MOVE] == 1) {
        set_entvar(iActivator, var_iuser3, get_entvar(iActivator, var_iuser3) | PREVENT_FLAGS);
        set_entvar(iActivator, var_velocity, NULL_VECTOR);
        set_entvar(iActivator, var_maxspeed, 1.0);
    }

    if(g_eCvars[NO_FIRE])
        set_member(iActivator, m_bIsDefusing, true);

    return PLUGIN_CONTINUE;
}

public rt_revive_loop_pre(const iEnt, const iPlayer, const iActivator, const Float:fTimer, Modes:eMode) {
    if(g_eCvars[BOMB] && rg_is_bomb_planted()) {
        NotifyClient(iActivator, print_team_red, "RT_BOMB");
        return PLUGIN_HANDLED;
    }

    if(g_eCvars[DUEL] && rg_users_count(false)) {
        NotifyClient(iActivator, print_team_red, "RT_DUEL");
        return PLUGIN_HANDLED;
    }

    if(g_eCvars[SURVIVOR] && rg_users_count(true)) {
        NotifyClient(iActivator, print_team_red, "RT_SURVIVOR");
        return PLUGIN_HANDLED;
    }

    if(g_eCvars[REMAINING_TIME] && rg_get_remaining_time() <= g_eCvars[REMAINING_TIME]) {
        NotifyClient(iActivator, print_team_red, "RT_REMAINING_TIME");
        return PLUGIN_HANDLED;
    }

    if(g_eCvars[NO_MOVE] == 2) {
        new Float:fVecPlOrigin[3], Float:fVecEntOrigin[3];
        get_entvar(iActivator, var_origin, fVecPlOrigin);
        get_entvar(iEnt, var_vuser4, fVecEntOrigin);

        if(vector_distance(fVecPlOrigin, fVecEntOrigin) > Float:get_entvar(iEnt, var_fuser2)) {
            NotifyClient(iActivator, print_team_red, "RT_MAX_DISTANCE");
            return PLUGIN_HANDLED;
        }
    }

    return PLUGIN_CONTINUE;
}

public rt_revive_loop_post(const iEnt, const iPlayer, const iActivator, const Float:fTimer, Modes:eMode) {
    if(g_eCvars[FORCE_FWD_MODE] && g_eCvars[NO_MOVE] == 1)
        set_entvar(iActivator, var_maxspeed, 1.0);
}

public rt_revive_cancelled(const iEnt, const iPlayer, const iActivator, const Modes:eMode) {
    if(iActivator == RT_NULLENT)
        return;

    if(g_eCvars[NO_MOVE] == 1) {
        set_entvar(iActivator, var_iuser3, get_entvar(iActivator, var_iuser3) & ~PREVENT_FLAGS);
        rg_reset_maxspeed(iActivator);
    }

    if(g_eCvars[NO_FIRE])
        set_member(iActivator, m_bIsDefusing, false);
}

public rt_revive_end(const iEnt, const iPlayer, const iActivator, const Modes:eMode) {
    switch(eMode) {
        case MODE_REVIVE: {
            new Modes:iMode = Modes:get_entvar(iEnt, var_iuser3);

            if(iMode != MODE_PLANT) {
                g_ePlayerData[iActivator][REVIVE_COUNT]++;

                rg_add_account(iActivator, -g_eCvars[REVIVE_COST]);
            }
        }
        case MODE_PLANT: { rg_add_account(iActivator, -g_eCvars[PLANTING_COST]); }
    }

    if(g_eCvars[NO_MOVE] == 1) {
        set_entvar(iActivator, var_iuser3, get_entvar(iActivator, var_iuser3) & ~PREVENT_FLAGS);
        rg_reset_maxspeed(iActivator);
    }

    if(g_eCvars[NO_FIRE])
        set_member(iActivator, m_bIsDefusing, false);
}

stock rg_users_count(const bool:bMode1x1 = false) {
    new iAliveTs, iAliveCTs;
    rg_initialize_player_counts(iAliveTs, iAliveCTs);

    if(!bMode1x1 && (iAliveTs == 1 && iAliveCTs == 1))
        return 1;

    if(bMode1x1 && (iAliveTs == 1 || iAliveCTs == 1))
        return 1;

    return 0;
}

stock Float:rg_get_remaining_time() {
    return (float(get_member_game(m_iRoundTimeSecs)) - get_gametime() + Float:get_member_game(m_fRoundStartTimeReal));
}

stock TeamName:rg_get_team_wins_row(const iWins) {
    if(get_member_game(m_iNumConsecutiveCTLoses) >= iWins)
        return TEAM_TERRORIST;

    if(get_member_game(m_iNumConsecutiveTerroristLoses) >= iWins)
        return TEAM_CT;

    return TEAM_UNASSIGNED;
}

public CreateCvars() {
    bind_pcvar_string(create_cvar(
        "rt_access",
        "",
        FCVAR_NONE,
        "Access flags for resurrection/planting"),
        g_eCvars[ACCESS],
        charsmax(g_eCvars[ACCESS])
    );
    bind_pcvar_num(create_cvar(
        "rt_max_revives",
        "3",
        FCVAR_NONE,
        "Maximum number of resurrections per round",
        true,
        1.0),
        g_eCvars[MAX_REVIVES]
    );
    bind_pcvar_num(create_cvar(
        "rt_max_spawns",
        "2",
        FCVAR_NONE,
        "Maximum number of spawns per player per round",
        true,
        1.0),
        g_eCvars[MAX_SPAWNS]
    );
    bind_pcvar_num(create_cvar(
        "rt_no_fire",
        "1",
        FCVAR_NONE,
        "Block shooting during resurrection/planting",
        true,
        0.0,
        true,
        1.0),
        g_eCvars[NO_FIRE]
    );
    bind_pcvar_num(create_cvar(
        "rt_bomb",
        "1",
        FCVAR_NONE,
        "You cannot resurrect/plant if there is a bomb",
        true,
        0.0,
        true,
        1.0),
        g_eCvars[BOMB]
    );
    bind_pcvar_num(create_cvar(
        "rt_duel",
        "1",
        FCVAR_NONE,
        "You can't resurrect/plant if there are 1x1 left",
        true,
        0.0,
        true,
        1.0),
        g_eCvars[DUEL]
    );
    bind_pcvar_num(create_cvar(
        "rt_survivor",
        "0",
        FCVAR_NONE,
        "You cannot resurrect/plant if there is 1 live player left in one of the teams",
        true,
        0.0,
        true,
        1.0),
        g_eCvars[SURVIVOR]
    );
    bind_pcvar_num(create_cvar(
        "rt_min_round",
        "1",
        FCVAR_NONE,
        "From which round is resurrection/planting available",
        true,
        1.0),
        g_eCvars[MIN_ROUND]
    );
    bind_pcvar_num(create_cvar(
        "rt_no_move",
        "1",
        FCVAR_NONE,
        "Unable to move during resurrection/planting. 0 - allowed, 1 - not allowed, 2 - allowed, but close to corpse",
        true,
        0.0,
        true,
        2.0),
        g_eCvars[NO_MOVE]
    );
    bind_pcvar_num(create_cvar(
        "rt_revive_cost",
        "0",
        FCVAR_NONE,
        "Cost of resurrection",
        true,
        0.0),
        g_eCvars[REVIVE_COST]
    );
    bind_pcvar_num(create_cvar(
        "rt_planting_cost",
        "0",
        FCVAR_NONE,
        "Cost of planting",
        true,
        0.0),
        g_eCvars[PLANTING_COST]
    );
    bind_pcvar_num(create_cvar(
        "rt_wins_domination",
        "5",
        FCVAR_NONE,
        "Prohibition of resurrection/planting for the dominant team(consecutive wins)",
        true,
        0.0),
        g_eCvars[WIN_DIFF]
    );
    bind_pcvar_float(create_cvar(
        "rt_remaining_time",
        "30.0",
        FCVAR_NONE,
        "Prohibition of resurrection/planting until the end of the round",
        true,
        0.0),
        g_eCvars[REMAINING_TIME]
    );

    new pCvar = get_cvar_pointer("rt_force_fwd_mode");

    if(pCvar)
        bind_pcvar_num(pCvar, g_eCvars[FORCE_FWD_MODE]);
}
Код:
#include <amxmodx>
#include <reapi>
#include <hamsandwich>
#include <fakemeta>
#include <rt_api>

public stock const PLUGIN[] = "Revive Teammates: Model";
public stock const CFG_FILE[] = "addons/amxmodx/configs/rt_configs/rt_revive_model.cfg";

enum CVARS {
    MODEL_V[96],
};

new g_eCvars[CVARS];

public plugin_precache() {
    CreateCvars();

    server_cmd("exec %s", CFG_FILE);
    server_exec();

    if(g_eCvars[MODEL_V][0]) {
        precache_model(g_eCvars[MODEL_V]);
        UTIL_PrecacheSoundsFromModel(g_eCvars[MODEL_V]);
    }
}

public plugin_init() {
    register_plugin(PLUGIN, VERSION, "mx?!");

    if(g_eCvars[MODEL_V][0]) {
        RegisterHookChain(RG_CBasePlayerWeapon_DefaultDeploy, "CBasePlayerWeapon_DefaultDeploy_Post", true);
    }
}

public plugin_cfg() {
    if(!g_eCvars[MODEL_V][0]) {
        return;
    }

    new pCvar = get_cvar_pointer("rt_force_fwd_mode"); // from rt_core.sma

    if(!pCvar) {
        return;
    }

    if(!get_pcvar_num(pCvar)) {
        set_pcvar_num(pCvar, 1);
        log_amx("Forcing 'rt_force_fwd_mode' cvar value to ^"1^" !");
    }
}

public rt_revive_start_post(const iEnt, const iPlayer, const iActivator, const Modes:eMode) {
    if(!g_eCvars[MODEL_V][0] || eMode != MODE_REVIVE) {
        return;
    }

    set_entvar(iActivator, var_viewmodel, g_eCvars[MODEL_V]);

    set_entvar(iActivator, var_weaponmodel, "");
    set_member(iActivator, m_szAnimExtention, "knife");

    const ANIM_DRAW = 3;
    SetWeaponAnim(iActivator, ANIM_DRAW);

    set_member(iActivator, m_flNextAttack, 9999.0);

    new pWeapon = get_member(iActivator, m_pActiveItem);
    if(pWeapon > 0) {
        set_member(pWeapon, m_Weapon_flTimeWeaponIdle, 9999.0);
        //set_member(pWeapon, m_Weapon_flNextPrimaryAttack, 9999.0);
        //set_member(pWeapon, m_Weapon_flNextSecondaryAttack, 9999.0);
    }
}

public rt_revive_loop_post(const iEnt, const iPlayer, const iActivator, const Float:fTimer, Modes:eMode) {
    const Float:fAnimTime = 0.6; // 23 frames / 30 fps = 0.766, но нам не нужна полная анимация, обрезаем 0.166
    const ANIM_USE = 1;

    new Float:fGameTime = get_gametime();
    new Float:fEndTime = fGameTime + fTimer;

    if(g_eCvars[MODEL_V][0] && eMode == MODE_REVIVE && fGameTime > (fEndTime - fAnimTime) && get_entvar(iActivator, var_weaponanim) != ANIM_USE) {
        SetWeaponAnim(iActivator, ANIM_USE);
    }
}

public rt_revive_cancelled(const iEnt, const iPlayer, const iActivator, const Modes:eMode) {
    if(eMode == MODE_REVIVE && iActivator != RT_NULLENT) {
        TryResetReviveModel(iActivator);
    }
}

public rt_revive_end(const iEnt, const iPlayer, const iActivator, const Modes:eMode) {
    if(eMode == MODE_REVIVE/* && iActivator != RT_NULLENT*/) {
        TryResetReviveModel(iActivator);
    }
}

TryResetReviveModel(pPlayer) {
    if(!g_eCvars[MODEL_V][0] || !IsRiviveModelActive(pPlayer)) {
        return;
    }

    new pWeapon = get_member(pPlayer, m_pActiveItem);

    if(!is_nullent(pWeapon)) {
        ExecuteHamB(Ham_Item_Deploy, pWeapon);
    }
}

bool:IsRiviveModelActive(pPlayer) {
/*
    if(!g_eCvars[MODEL_V][0]) {
        return false;
    }
*/

    static szModel[96]
    get_entvar(pPlayer, var_viewmodel, szModel, charsmax(szModel));

    return bool:equal(szModel, g_eCvars[MODEL_V]);
}

public CBasePlayerWeapon_DefaultDeploy_Post(pWeapon, szViewModel[], szWeaponModel[], iAnim, szAnimExt[], skiplocal) {
    if(!is_entity(pWeapon)) {
        return;
    }

    new pPlayer = get_member(pWeapon, m_pPlayer);

    if(rt_get_user_mode(pPlayer) == MODE_REVIVE) {
        rt_reset_use(pPlayer);
    }
}

CreateCvars() {
    bind_pcvar_string(create_cvar(
        "rt_revive_model_v",
        "",
        FCVAR_NONE,
        "1st persion view model for revive process"),
        g_eCvars[MODEL_V],
        charsmax(g_eCvars[MODEL_V])
    );
}

SetWeaponAnim(pPlayer, iAnimNum) {
    set_entvar(pPlayer, var_weaponanim, iAnimNum);

    message_begin(MSG_ONE_UNRELIABLE, SVC_WEAPONANIM, .player = pPlayer);
    write_byte(iAnimNum); // sequence number
    write_byte(0); // weaponmodel bodygroup.
    message_end();
}

// Автопрекеш звуков из модели: https://dev-cs.ru/resources/914/field?field=source
stock UTIL_PrecacheSoundsFromModel(const szModelPath[])
{
    new iFile;

    if((iFile = fopen(szModelPath, "rt")))
    {
        new szSoundPath[64];

        new iNumSeq, iSeqIndex;
        new iEvent, iNumEvents, iEventIndex;

        fseek(iFile, 164, SEEK_SET);
        fread(iFile, iNumSeq, BLOCK_INT);
        fread(iFile, iSeqIndex, BLOCK_INT);

        for(new k, i = 0; i < iNumSeq; i++)
        {
            fseek(iFile, iSeqIndex + 48 + 176 * i, SEEK_SET);
            fread(iFile, iNumEvents, BLOCK_INT);
            fread(iFile, iEventIndex, BLOCK_INT);
            fseek(iFile, iEventIndex + 176 * i, SEEK_SET);

            for(k = 0; k < iNumEvents; k++)
            {
                fseek(iFile, iEventIndex + 4 + 76 * k, SEEK_SET);
                fread(iFile, iEvent, BLOCK_INT);
                fseek(iFile, 4, SEEK_CUR);

                if(iEvent != 5004)
                    continue;

                fread_blocks(iFile, szSoundPath, 64, BLOCK_CHAR);

                if(strlen(szSoundPath))
                {
                    strtolower(szSoundPath);
                    engfunc(EngFunc_PrecacheSound, szSoundPath);
                }
            }
        }
    }

    fclose(iFile);
}
Код:
#include <amxmodx>
#include <fakemeta>
#include <hamsandwich>
#include <reapi>
#include <rt_api>

public stock const PLUGIN[] = "Revive Teammates: Sounds";
public stock const CFG_FILE[] = "addons/amxmodx/configs/rt_configs/rt_sounds.cfg";
public stock const INI_FILE[] = "addons/amxmodx/configs/rt_configs/rt_sounds.ini";

#define MAX_SOUNDS_PER_SECTION 10
#define MAX_SOUND_LENGTH 64

enum CVARS {
    Float:SOUND_RADIUS,
    NEARBY_PLAYERS,
    FORCE_FWD_MODE
};

new g_eCvars[CVARS];

enum sections_struct {
    SECTION_REVIVE_START,
    SECTION_REVIVE_LOOP,
    SECTION_REVIVE_END,
    SECTION_PLANT_START,
    SECTION_PLANT_LOOP,
    SECTION_PLANT_END
};

new sections_struct:g_eCurrentSection;
new g_iSounds[sections_struct];
new g_szSounds[sections_struct][MAX_SOUNDS_PER_SECTION][MAX_SOUND_LENGTH];
new g_iTicks[MAX_PLAYERS + 1];

public plugin_precache() {
    register_plugin(PLUGIN, VERSION, AUTHORS);

    if(!file_exists(INI_FILE)) {
        set_fail_state("[RT Sounds] File ^"%s^" not found", INI_FILE);
        return;
    }

    new INIParser:iParser = INI_CreateParser();
    INI_SetReaders(iParser, "ReadKeyValue", "ReadNewSection");
    INI_ParseFile(iParser, INI_FILE);
    INI_DestroyParser(iParser);

    CreateCvars();

    server_cmd("exec %s", CFG_FILE);
    server_exec();
}

public rt_revive_start(const iEnt, const iPlayer, const iActivator, const Modes:eMode) {
    g_iTicks[iActivator] = 0;

    switch(eMode) {
        case MODE_REVIVE: { PlaybackSound(iEnt, iPlayer, iActivator, SECTION_REVIVE_START); }
        case MODE_PLANT: { PlaybackSound(iEnt, iPlayer, iActivator, SECTION_PLANT_START); }
    }
}

public rt_revive_loop_post(const iEnt, const iPlayer, const iActivator, const Float:fTimer, Modes:eMode) {
    if(!g_eCvars[FORCE_FWD_MODE] || ++g_iTicks[iActivator] == 10) {
        g_iTicks[iActivator] = 0;

        switch(eMode) {
            case MODE_REVIVE: { PlaybackSound(iEnt, iPlayer, iActivator, SECTION_REVIVE_LOOP); }
            case MODE_PLANT: { PlaybackSound(iEnt, iPlayer, iActivator, SECTION_PLANT_LOOP); }
        }
    }
}

public rt_revive_end(const iEnt, const iPlayer, const iActivator, const Modes:eMode) {
    switch(eMode) {
        case MODE_REVIVE: {
            new Modes:iMode = Modes:get_entvar(iEnt, var_iuser3);

            if(iMode != MODE_PLANT)
                PlaybackSound(iEnt, iPlayer, iActivator, SECTION_REVIVE_END);
        }
        case MODE_PLANT: { PlaybackSound(iEnt, iPlayer, iActivator, SECTION_PLANT_END); }
    }
}

public bool:ReadNewSection(INIParser:iParser, const szSection[], bool:bInvalidTokens, bool:bCloseBracket) {
    if(!bCloseBracket) {
        log_error(AMX_ERR_NATIVE, "Closing bracket was not detected! Current section name '%s'.", szSection);
        return false;
    }

    if(equal(szSection, "revive_start")) {
        g_eCurrentSection = SECTION_REVIVE_START;
        return true;
    } else if(equal(szSection, "revive_loop")) {
        g_eCurrentSection = SECTION_REVIVE_LOOP;
        return true;
    } else if(equal(szSection, "revive_end")) {
        g_eCurrentSection = SECTION_REVIVE_END;
        return true;
    } else if(equal(szSection, "plant_start")) {
        g_eCurrentSection = SECTION_PLANT_START;
        return true;
    } else if(equal(szSection, "plant_loop")) {
        g_eCurrentSection = SECTION_PLANT_LOOP;
        return true;
    } else if(equal(szSection, "plant_end")) {
        g_eCurrentSection = SECTION_PLANT_END;
        return true;
    }

    return false;
}

public bool:ReadKeyValue(INIParser:iParser, const szKey[], const szValue[]) {
    if(szKey[0] == EOS)
        return false;

    new szSound[MAX_SOUND_LENGTH];
    copy(szSound, charsmax(szSound), szKey);
    trim(szSound);
    copy(g_szSounds[g_eCurrentSection][g_iSounds[g_eCurrentSection]++], charsmax(g_szSounds[][]), szSound);

    precache_sound(szSound);

    return true;
}

stock PlaybackSound(const iEnt, const iPlayer, const iActivator, const sections_struct:iSoundSection) {
    if(g_iSounds[iSoundSection]) {
        if(g_eCvars[NEARBY_PLAYERS] == 2 || (g_eCvars[NEARBY_PLAYERS] && (iSoundSection == SECTION_REVIVE_END || iSoundSection == SECTION_PLANT_END)))
            PlaybackSoundNearbyPlayers(iEnt, g_szSounds[iSoundSection][random(g_iSounds[iSoundSection])]);
        else if(!g_eCvars[NEARBY_PLAYERS]) {
            rg_send_audio(iActivator, g_szSounds[iSoundSection][random(g_iSounds[iSoundSection])]);
            rg_send_audio(iPlayer, g_szSounds[iSoundSection][random(g_iSounds[iSoundSection])]);
        }
    }
}

stock PlaybackSoundNearbyPlayers(const iPlayer, const szSound[]) {
    new iEnt = RT_NULLENT;

    new Float:fVecOrigin[3];
    get_entvar(iPlayer, var_vuser4, fVecOrigin);

    while((iEnt = engfunc(EngFunc_FindEntityInSphere, iEnt, fVecOrigin, g_eCvars[SOUND_RADIUS])) > 0)
        if(ExecuteHam(Ham_IsPlayer, iEnt))
            rg_send_audio(iEnt, szSound);
}

public CreateCvars() {
    bind_pcvar_float(create_cvar(
        "rt_sound_radius",
        "250.0",
        FCVAR_NONE,
        "The radius in which to count the nearest players",
        true,
        1.0),
        g_eCvars[SOUND_RADIUS]
    );
    bind_pcvar_num(create_cvar(
        "rt_nearby_players",
        "0",
        FCVAR_NONE,
        "Play the resurrection/landing sound for nearby players. 0 - off, 1 - only ending sounds, 2 - all sounds",
        true,
        0.0,
        true,
        2.0),
        g_eCvars[NEARBY_PLAYERS]
    );

    new pCvar = get_cvar_pointer("rt_force_fwd_mode");

    if(pCvar)
        bind_pcvar_num(pCvar, g_eCvars[FORCE_FWD_MODE]);
}
Код:
#include <amxmodx>
#include <reapi>
#include <rt_api>

public stock const PLUGIN[] = "Revive Teammates: Timer";
public stock const CFG_FILE[] = "addons/amxmodx/configs/rt_configs/rt_timer.cfg";

enum CVARS {
    TIMER_TYPE,
    REVIVE_COLORS[MAX_COLORS_LENGTH],
    REVIVE_COORDS[MAX_COORDS_LENGTH],
    PLANTING_COLORS[MAX_COLORS_LENGTH],
    PLANTING_COORDS[MAX_COORDS_LENGTH],
    FORCE_FWD_MODE
};

new g_eCvars[CVARS];

enum HudData {
    COLOR_R,
    COLOR_G,
    COLOR_B,
    Float:COORD_X,
    Float:COORD_Y
};

new g_eHudData[Modes][HudData];

enum TimeData {
    Float:GLOBAL_TIME,
    CEIL_TIME,
    Float:START_TIME,
};

new g_eTimeData[TimeData];

new const TIMER_BEGIN[]         = "[ | ";
new const TIMER_ADD[]           = "- ";
new const TIMER_END[]           = "]";
new const TIMER_REPLACE_SYMB[]  = "| -";
new const TIMER_REPLACE_WITH[]  = "| |";

new g_szTimer[MAX_PLAYERS + 1][64];
new g_iHudSyncObj;
new g_iTicks[MAX_PLAYERS + 1];

public plugin_precache() {
    CreateCvars();

    server_cmd("exec %s", CFG_FILE);
    server_exec();

    new szHudColors[3][4];

    if(parse(g_eCvars[REVIVE_COLORS], szHudColors[0], charsmax(szHudColors[]),
    szHudColors[1], charsmax(szHudColors[]), szHudColors[2], charsmax(szHudColors[])) == 3) {
        g_eHudData[MODE_REVIVE][COLOR_R] = str_to_num(szHudColors[0]);
        g_eHudData[MODE_REVIVE][COLOR_G] = str_to_num(szHudColors[1]);
        g_eHudData[MODE_REVIVE][COLOR_B] = str_to_num(szHudColors[2]);
    }

    if(parse(g_eCvars[PLANTING_COLORS], szHudColors[0], charsmax(szHudColors[]),
    szHudColors[1], charsmax(szHudColors[]), szHudColors[2], charsmax(szHudColors[])) == 3) {
        g_eHudData[MODE_PLANT][COLOR_R] = str_to_num(szHudColors[0]);
        g_eHudData[MODE_PLANT][COLOR_G] = str_to_num(szHudColors[1]);
        g_eHudData[MODE_PLANT][COLOR_B] = str_to_num(szHudColors[2]);
    }

    new szHudCoords[2][8];

    if(parse(g_eCvars[REVIVE_COORDS], szHudCoords[0], charsmax(szHudCoords[]), szHudCoords[1], charsmax(szHudCoords[])) == 2) {
        g_eHudData[MODE_REVIVE][COORD_X] = str_to_float(szHudCoords[0]);
        g_eHudData[MODE_REVIVE][COORD_Y] = str_to_float(szHudCoords[1]);
    }

    if(parse(g_eCvars[PLANTING_COORDS], szHudCoords[0], charsmax(szHudCoords[]), szHudCoords[1], charsmax(szHudCoords[])) == 2) {
        g_eHudData[MODE_PLANT][COORD_X] = str_to_float(szHudCoords[0]);
        g_eHudData[MODE_PLANT][COORD_Y] = str_to_float(szHudCoords[1]);
    }
}

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

    register_dictionary("rt_library.txt");

    if(!g_eCvars[TIMER_TYPE])
        g_iHudSyncObj = CreateHudSyncObj();

    g_eTimeData[GLOBAL_TIME] = get_pcvar_float(get_cvar_pointer("rt_revive_time"));
    g_eTimeData[CEIL_TIME] = floatround(g_eTimeData[GLOBAL_TIME], floatround_ceil);
    g_eTimeData[START_TIME] = (1.0 - g_eTimeData[GLOBAL_TIME] / float(g_eTimeData[CEIL_TIME])) * 100.0;
}

public rt_revive_start(const iEnt, const iPlayer, const iActivator, const Modes:eMode) {
    g_iTicks[iActivator] = 0;

    switch(g_eCvars[TIMER_TYPE]) {
        case 0: {
            formatex(g_szTimer[iPlayer], charsmax(g_szTimer[]), TIMER_BEGIN);

            for(new i; i < floatround(g_eTimeData[GLOBAL_TIME]); i++)
                add(g_szTimer[iPlayer], charsmax(g_szTimer[]), TIMER_ADD);

            add(g_szTimer[iPlayer], charsmax(g_szTimer[]), TIMER_END);

            DisplayHudMessage(iPlayer, iActivator, eMode);
        }
        case 1: {
            rg_send_bartime2(iActivator, g_eTimeData[CEIL_TIME], g_eTimeData[START_TIME]);

            if(eMode == MODE_REVIVE && is_user_connected(iPlayer))
                rg_send_bartime2(iPlayer, g_eTimeData[CEIL_TIME], g_eTimeData[START_TIME]);
        }
    }
}

public rt_revive_loop_post(const iEnt, const iPlayer, const iActivator, const Float:fTimer, Modes:eMode) {
    if(!g_eCvars[FORCE_FWD_MODE] || ++g_iTicks[iActivator] == 10) {
        g_iTicks[iActivator] = 0;

        if(!g_eCvars[TIMER_TYPE]) {
            replace(g_szTimer[iPlayer], charsmax(g_szTimer[]), TIMER_REPLACE_SYMB, TIMER_REPLACE_WITH);

            DisplayHudMessage(iPlayer, iActivator, eMode);
        }
    }
}

public rt_revive_cancelled(const iEnt, const iPlayer, const iActivator, const Modes:eMode) {
    switch(g_eCvars[TIMER_TYPE]) {
        case 0: {
            if(iActivator != RT_NULLENT)
                ClearSyncHud(iActivator, g_iHudSyncObj);
        }
        case 1: {
            if(iActivator != RT_NULLENT)
                rg_send_bartime(iActivator, 0);

            if(eMode == MODE_REVIVE && iPlayer != RT_NULLENT)
                rg_send_bartime(iPlayer, 0);
        }
    }
}

stock DisplayHudMessage(const iPlayer, const iActivator, const Modes:eMode) {
    set_hudmessage(g_eHudData[eMode][COLOR_R], g_eHudData[eMode][COLOR_G], g_eHudData[eMode][COLOR_B],
    g_eHudData[eMode][COORD_X], g_eHudData[eMode][COORD_Y], .holdtime = g_eTimeData[GLOBAL_TIME]);
    ShowSyncHudMsg(iActivator, g_iHudSyncObj, g_szTimer[iPlayer]);
}

public CreateCvars() {
    bind_pcvar_num(create_cvar(
        "rt_timer_type",
        "1",
        FCVAR_NONE,
        "0 - HUD, 1 - bartime(orange line)",
        true,
        0.0,
        true,
        1.0),
        g_eCvars[TIMER_TYPE]
    );
    bind_pcvar_string(create_cvar(
        "rt_revive_hud_colors",
        "0 255 0",
        FCVAR_NONE,
        "HUD's colors at resurrection"),
        g_eCvars[REVIVE_COLORS],
        charsmax(g_eCvars[REVIVE_COLORS])
    );
    bind_pcvar_string(create_cvar(
        "rt_revive_hud_coords",
        "-1.0 0.6",
        FCVAR_NONE,
        "HUD's coordinates at resurrection"),
        g_eCvars[REVIVE_COORDS],
        charsmax(g_eCvars[REVIVE_COORDS])
    );
    bind_pcvar_string(create_cvar(
        "rt_planting_hud_colors",
        "255 0 0",
        FCVAR_NONE,
        "HUD's colors at planting"),
        g_eCvars[PLANTING_COLORS],
        charsmax(g_eCvars[PLANTING_COLORS])
    );
    bind_pcvar_string(create_cvar(
        "rt_planting_hud_coords",
        "-1.0 0.6",
        FCVAR_NONE,
        "HUD's coordinates at planting"),
        g_eCvars[PLANTING_COORDS],
        charsmax(g_eCvars[PLANTING_COORDS])
    );

    new pCvar = get_cvar_pointer("rt_force_fwd_mode");

    if(pCvar)
        bind_pcvar_num(pCvar, g_eCvars[FORCE_FWD_MODE]);
}
Верх Низ