Иконка ресурса

[ReAPI] Damager 1.0.0

Нет прав для скачивания
Код:
////////////////////////////////    HEADER    ////////////////////////////////

#include <amxmodx>
#include <fakemeta>
#include <hamsandwich>
#include <nvault_array>
#include <reapi>
#include <time>
#include <xs>

#define PLUGIN_NAME     "[ReAPI] Damager"
#define PLUGIN_VERSION  "1.0.0"
#define PLUGIN_AUTHOR   "steelzzz & Albertio"

////////////////////////////////    CONSTANTS    ////////////////////////////////

// The path to the configuration file
new const CFG_FILE_PATH[] = "addons/amxmodx/configs/reapi_damager/reapi_damager.ini";

// The name of the dictionary file
new const DICT_FILE_PATH[] = "reapi_damager.txt";

// The name of the nVault file
new const NVAULT_FILE[] = "reapi_damager";

////////////////////////////////    GLOBAL VARIABLES    ////////////////////////////////

enum Sections {
    SECTION_NONE = -1,
    SECTION_SETTINGS
};
new Sections:ParserCurSection;

enum DamagerDataStruct {
    DD_THROUGH_WALLS,
    DD_THROUGH_SMOKE,
    DD_NVAULT_EXPIRE_TIME,
    Float:DD_SMOKE_RADIUS
};
new DamagerData[DamagerDataStruct];

new Array:DamagerCmds;
new DamagerCmdsNum;

enum _:PlayerDataStruct {
    PD_STATE = 0,
    PD_STYLE,
    PD_TYPE,
    PD_INCOMING,
    PD_COLOR,
    PD_INCOMING_COLOR,
    PD_THROUGH_WALLS,
    PD_THROUGH_SMOKE,
    PD_POSITION,
    PD_AUTHID[MAX_AUTHID_LENGTH]
};
new PlayerData[MAX_PLAYERS + 1][PlayerDataStruct];

enum _:LastDamageStruct {
    Float:TIME = 0,
    Float:DAMAGE
};
new LastDamage[MAX_PLAYERS + 1][LastDamageStruct];

enum _:DamagerState {
    DISABLED = 0,
    ENABLED
};

enum _:DamagerStyle {
    NUMBERS = 0,
    STARS
};

enum _:DamagerType {
    DEFAULT = 0,
    CIRCLE
};

enum _:DamagerColor {
    COLOR_RANDOM = 0,
    COLOR_WHITE,
    COLOR_RED,
    COLOR_GREEN,
    COLOR_BLUE,
    COLOR_YELLOW,
    COLOR_MAGENTA,
    COLOR_CYAN
};

new const DamagerColors[][][] = {
    { "COLOR_RANDOM",  { 0,   0,   0   } },
    { "COLOR_WHITE",   { 255, 255, 255 } },
    { "COLOR_RED",     { 255, 0,   0   } },
    { "COLOR_GREEN",   { 0,   255, 0   } },
    { "COLOR_BLUE",    { 0,   0,   255 } },
    { "COLOR_YELLOW",  { 255, 255, 0   } },
    { "COLOR_MAGENTA", { 255, 0,   255 } },
    { "COLOR_CYAN",    { 0,   255, 255 } }
};

new const Float:DamagerCoords[][] = {
    { 0.50, 0.40 },
    { 0.56, 0.44 },
    { 0.60, 0.50 },
    { 0.56, 0.56 },
    { 0.50, 0.60 },
    { 0.44, 0.56 },
    { 0.40, 0.50 },
    { 0.44, 0.44 }
};

new HudSyncObjs[8];

new nVaultHandle;

new Array:ArrayActiveSmokes;

new bool:ShootsThroughSmoke[MAX_PLAYERS + 1];

////////////////////////////////    CONFIGURATION    ////////////////////////////////

public plugin_precache() {
    ParseConfig();
}

public ParseConfig() {
    DamagerCmds = ArrayCreate(32);

    new INIParser:parser = INI_CreateParser();
    INI_SetReaders(parser, "ReadKeyValue", "ReadNewSection");
    INI_ParseFile(parser, CFG_FILE_PATH);
    INI_DestroyParser(parser);

    DamagerCmdsNum = ArraySize(DamagerCmds);
}

public bool:ReadNewSection(INIParser:parser, const section[], bool:invalidTokens, bool:closeBracket) {  
    if(!closeBracket) {
        log_amx("Closing bracket was not detected! Current section name '%s'.", section);
        return false;
    }

    if(equal(section, "settings")) {
        ParserCurSection = SECTION_SETTINGS;
        return true;
    }

    return false;
}

public bool:ReadKeyValue(INIParser:parser, const key[], const value[]) {
    switch(ParserCurSection) {
        case SECTION_NONE: {
            return false;
        }
        case SECTION_SETTINGS: {
            if(equal(key, "THROUGH_WALLS")) {
                DamagerData[DD_THROUGH_WALLS] = str_to_num(value);
            } else if(equal(key, "THROUGH_SMOKE")) {
                DamagerData[DD_THROUGH_SMOKE] = str_to_num(value);
            } else if(equal(key, "NVAULT_EXPIRE_TIME")) {
                DamagerData[DD_NVAULT_EXPIRE_TIME] = str_to_num(value);
            } else if(equal(key, "SMOKE_RADIUS")) {
                DamagerData[DD_SMOKE_RADIUS] = str_to_float(value);
            } else if(equal(key, "CHAT_COMMANDS")) {
                new cmd[32], allCmds[MAX_FMT_LENGTH];
                copy(allCmds, charsmax(allCmds), value);

                while(allCmds[0] != 0 && strtok(allCmds, cmd, charsmax(cmd), allCmds, charsmax(allCmds), ',')) {
                    trim(cmd), trim(allCmds);
                    ArrayPushString(DamagerCmds, cmd);
                }
            }
        }
    }

    return true;
}

public plugin_init() {
    register_plugin(PLUGIN_NAME, PLUGIN_VERSION, PLUGIN_AUTHOR);
    register_dictionary(DICT_FILE_PATH);

    RegisterCmds();
    RegisterHooks();

    for(new i; i < sizeof(HudSyncObjs); i++)
        HudSyncObjs[i] = CreateHudSyncObj();

    ArrayActiveSmokes = ArrayCreate();
}

public RegisterCmds() {
    for(new i, cmd[32]; i < DamagerCmdsNum; i++) {
        ArrayGetString(DamagerCmds, i, cmd, charsmax(cmd));

        register_clcmd(fmt("say %s", cmd), "ShowDamagerMenu");
        register_clcmd(fmt("say_team %s", cmd), "ShowDamagerMenu");
    }
}

public RegisterHooks() {
    RegisterHookChain(RG_CBasePlayer_TakeDamage, "Player_TakeDamage_Post", true);
    RegisterHookChain(RG_CBasePlayer_TraceAttack, "Player_TraceAttack_Post", true);
   
    RegisterHookChain(RG_CGrenade_ExplodeSmokeGrenade, "Grenade_ExplodeSmokeGrenade_Post", true);
    RegisterHam(Ham_StopSneaking, "grenade", "Grenade_StopSneaking_Post", true);
}

public plugin_cfg() {
    NVaultInit();
}

////////////////////////////////    MAIN FUNCTIONS    ////////////////////////////////

public client_authorized(playerId, const authId[]) {
    if(is_user_bot(playerId) || is_user_hltv(playerId))
        return;

    copy(PlayerData[playerId][PD_AUTHID], charsmax(PlayerData[][PD_AUTHID]), authId);

    if(nvault_get_array(nVaultHandle, PlayerData[playerId][PD_AUTHID], PlayerData[playerId], PlayerDataStruct) <= 0) {
        PlayerData[playerId][PD_STATE] = ENABLED;
        PlayerData[playerId][PD_STYLE] = NUMBERS;
        PlayerData[playerId][PD_TYPE] = CIRCLE;
        PlayerData[playerId][PD_INCOMING] = ENABLED;
        PlayerData[playerId][PD_COLOR] = COLOR_GREEN;
        PlayerData[playerId][PD_INCOMING_COLOR] = COLOR_RED;
        PlayerData[playerId][PD_THROUGH_WALLS] = (DamagerData[DD_THROUGH_WALLS] == ENABLED) ? ENABLED : DISABLED;
        PlayerData[playerId][PD_THROUGH_SMOKE] = (DamagerData[DD_THROUGH_SMOKE] == ENABLED) ? ENABLED : DISABLED;

        NVaultSaveData(playerId);
    }
}

public ShowDamagerMenu(const playerId) {
    SetGlobalTransTarget(playerId);

    new menuItem[MAX_FMT_LENGTH];
    new menu = menu_create(menuItem, "HandlerDamagerMenu");
   
    BuildDamagerMenu(playerId, menu);
   
    formatex(menuItem, charsmax(menuItem), "%l", "MENU_EXIT");
    menu_setprop(menu, MPROP_EXITNAME, menuItem);
   
    menu_setprop(menu, MPROP_PERPAGE, 0);
    menu_setprop(menu, MPROP_EXIT, MEXIT_FORCE);

    menu_display(playerId, menu);
    return PLUGIN_HANDLED;
}

public BuildDamagerMenu(const playerId, const menu) {
    new menuItem[MAX_FMT_LENGTH];

    formatex(menuItem, charsmax(menuItem), "%l", "MENU_ITEM1", (PlayerData[playerId][PD_STATE] == ENABLED) ? "ENABLED" : "DISABLED");
    menu_additem(menu, menuItem);
   
    formatex(menuItem, charsmax(menuItem), "%l", "MENU_ITEM2", (PlayerData[playerId][PD_STYLE] == STARS) ? "STARS" : "NUMBERS");
    menu_additem(menu, menuItem);

    formatex(menuItem, charsmax(menuItem), "%l", "MENU_ITEM3", (PlayerData[playerId][PD_TYPE] == CIRCLE) ? "CIRCLE" : "DEFAULT");
    menu_additem(menu, menuItem);

    formatex(menuItem, charsmax(menuItem), "%l", "MENU_ITEM4", (PlayerData[playerId][PD_INCOMING] == ENABLED) ? "ENABLED" : "DISABLED");
    menu_additem(menu, menuItem);

    formatex(menuItem, charsmax(menuItem), "%l", "MENU_ITEM5", DamagerColors[PlayerData[playerId][PD_COLOR]][0][0]);
    menu_additem(menu, menuItem);

    formatex(menuItem, charsmax(menuItem), "%l", "MENU_ITEM6", DamagerColors[PlayerData[playerId][PD_INCOMING_COLOR]][0][0]);
    menu_additem(menu, menuItem);

    if(DamagerData[DD_THROUGH_WALLS] == ENABLED) {
        formatex(menuItem, charsmax(menuItem), "%l", "MENU_ITEM7", (PlayerData[playerId][PD_THROUGH_WALLS] == ENABLED) ? "ENABLED" : "DISABLED");
        menu_additem(menu, menuItem);
    } else {
        menu_addblank2(menu);
    }

    if(DamagerData[DD_THROUGH_SMOKE] == ENABLED) {
        formatex(menuItem, charsmax(menuItem), "%l", "MENU_ITEM8", (PlayerData[playerId][PD_THROUGH_SMOKE] == ENABLED) ? "ENABLED" : "DISABLED");
        menu_additem(menu, menuItem);
    } else {
        menu_addblank2(menu);
    }

    menu_addblank2(menu);
}

public HandlerDamagerMenu(const playerId, menu, item) {
    if(item == MENU_EXIT) {
        if(PlayerData[playerId][PD_AUTHID][0] != EOS)
            NVaultSaveData(playerId);

        menu_destroy(menu);
        return PLUGIN_HANDLED;
    }
   
    switch(item) {
        case 4: {
            if(PlayerData[playerId][PD_COLOR] == charsmax(DamagerColors)) {
                PlayerData[playerId][PD_COLOR] = 0;
            } else {
                PlayerData[playerId][PD_COLOR]++;
            }
        }
        case 5: {
            if(PlayerData[playerId][PD_INCOMING_COLOR] == charsmax(DamagerColors)) {
                PlayerData[playerId][PD_INCOMING_COLOR] = 0;
            } else {
                PlayerData[playerId][PD_INCOMING_COLOR]++;
            }
        }
        default: {
            PlayerData[playerId][item] = !PlayerData[playerId][item];
        }
    }

    menu_destroy(menu);
    ShowDamagerMenu(playerId);
    return PLUGIN_HANDLED;
}

public Player_TakeDamage_Post(const victimId, inflictorId, attackerId, Float:damage, bitsDamageType) {
    if(!CheckIfDamagerCanWork(attackerId, victimId, damage, bitsDamageType))
        return;

    new attackerColor = GetAttackerDamagerColor(attackerId);
    new victimColor = GetVictimDamagerColor(victimId);

    if(PlayerData[attackerId][PD_TYPE] == CIRCLE) {
        ShowCircleDamager(attackerId, victimId, damage, attackerColor, victimColor);
    } else {
        ShowDamager(attackerId, victimId, damage, bitsDamageType, attackerColor, victimColor);
    }
}

public Player_TraceAttack_Post(const victimId, attackerId, Float:damage, Float:vecDir[3], trace) {
    if(!is_user_alive(attackerId))
        return;

    if((PlayerData[victimId][PD_STATE] == DISABLED) && (PlayerData[attackerId][PD_STATE] == DISABLED))
        return;

    ShootsThroughSmoke[attackerId] = false;

    new Float:vecStart[3];
    ExecuteHam(Ham_Player_GetGunPosition, attackerId, vecStart);

    new Float:vecEnd[3];
    get_tr2(trace, TR_vecEndPos, vecEnd);

    if(FindLineIntersectsSmoke(vecStart, vecEnd))
        ShootsThroughSmoke[attackerId] = true;
}

public Grenade_ExplodeSmokeGrenade_Post(const grenadeId) {
    ArrayPushCell(ArrayActiveSmokes, grenadeId);
}

public Grenade_StopSneaking_Post(const grenadeId) {
    new itemIndex = ArrayFindValue(ArrayActiveSmokes, grenadeId);

    if(itemIndex >= 0)
        ArrayDeleteItem(ArrayActiveSmokes, itemIndex);
}

////////////////////////////////    STOCK FUNCTIONS    ////////////////////////////////

stock NVaultInit() {
    NVaultOpen();
    NVaultCheckVersion();

    if(DamagerData[DD_NVAULT_EXPIRE_TIME])
        nvault_prune(nVaultHandle, 0, get_systime() - (SECONDS_IN_DAY * DamagerData[DD_NVAULT_EXPIRE_TIME]));
}

stock NVaultOpen() {
    if((nVaultHandle = nvault_open(NVAULT_FILE)) == INVALID_HANDLE)
        set_fail_state("Error opening nVault!");
}

stock NVaultCheckVersion() {
    new nVaultVersion[12];
    nvault_get(nVaultHandle, "version", nVaultVersion, charsmax(nVaultVersion));

    if(!equal(PLUGIN_VERSION, nVaultVersion)) {
        nvault_close(nVaultHandle);
       
        new dataDir[MAX_RESOURCE_PATH_LENGTH];
        get_localinfo("amxx_datadir", dataDir, charsmax(dataDir));

        delete_file(fmt("%s/vault/%s.vault", dataDir, NVAULT_FILE));
        delete_file(fmt("%s/vault/%s.journal", dataDir, NVAULT_FILE));

        NVaultOpen();

        nvault_set(nVaultHandle, "version", PLUGIN_VERSION);
    }
}

stock NVaultSaveData(const playerId) {
    nvault_set_array(nVaultHandle, PlayerData[playerId][PD_AUTHID], PlayerData[playerId], PlayerDataStruct);
}

stock bool:CheckIfDamagerCanWork(const attackerId, const victimId, const Float:damage, const bitsDamageType) {
    if(!is_user_connected(attackerId))
        return false;

    if((PlayerData[victimId][PD_STATE] == DISABLED) && (PlayerData[attackerId][PD_STATE] == DISABLED))
        return false;

    if(bitsDamageType & DMG_BLAST)
        return false;

    if(victimId == attackerId)
        return false;

    if(!rg_is_player_can_takedamage(victimId, attackerId))
        return false;

    if(FloatNearlyEqualOrLess(damage, 0.0))
        return false;

    if(!CheckVisibilityForDamage(attackerId, victimId))
        return false;

    return true;
}

stock ShowCircleDamager(const attackerId, const victimId, const Float:damage, const attackerColor, const victimColor) {
    new pos = ++PlayerData[attackerId][PD_POSITION];

    if(pos == sizeof(DamagerCoords))
        pos = PlayerData[attackerId][PD_POSITION] = 0;

    if(PlayerData[victimId][PD_INCOMING] == ENABLED)
        ShowHudToPlayer(victimId, HudSyncObjs[pos], victimColor, DamagerCoords[pos][0], DamagerCoords[pos][1] + 0.06, damage);

    ShowHudToPlayer(attackerId, HudSyncObjs[pos], attackerColor, DamagerCoords[pos][0], DamagerCoords[pos][1], damage);
}

stock ShowDamager(const attackerId, const victimId, const Float:damage, const bitsDamageType, const attackerColor, const victimColor) {
    if(bitsDamageType & DMG_GRENADE) {
        new Float:damageTime = get_gametime();

        if(FloatNearlyEqual((damageTime - LastDamage[attackerId][TIME]), 0.0)) {
            LastDamage[attackerId][DAMAGE] += damage;
        } else {
            LastDamage[attackerId][DAMAGE] = damage;
        }

        LastDamage[attackerId][TIME] = damageTime;

        if(PlayerData[victimId][PD_INCOMING] == ENABLED)
            ShowHudToPlayer(victimId, HudSyncObjs[0], victimColor, -1.0, 0.45, LastDamage[attackerId][DAMAGE]);

        ShowHudToPlayer(attackerId, HudSyncObjs[0], attackerColor, -1.0, 0.55, LastDamage[attackerId][DAMAGE]);
       
        return;
    }

    if(PlayerData[victimId][PD_INCOMING] == ENABLED)
        ShowHudToPlayer(victimId, HudSyncObjs[0], victimColor, -1.0, 0.45, damage);

    ShowHudToPlayer(attackerId, HudSyncObjs[0], attackerColor, -1.0, 0.55, damage);
}

stock bool:FloatNearlyEqualOrLess(const Float:value1, const Float:value2) {
    return bool:(value1 <= value2);
}

stock bool:FloatNearlyEqual(const Float:value1, const Float:value2) {
    return bool:((value1 == value2) || (floatabs(value1 - value2) < 0.001));
}

stock bool:CheckVisibilityForDamage(const attackerId, const victimId) {
    if(CheckPlayerIsBehindWall(attackerId, victimId))
        return false;

    if(CheckPlayerIsBehindSmoke(attackerId))
        return false;
   
    return true;
}

stock bool:CheckPlayerIsBehindWall(const attackerId, const victimId) {
    new bool:victimIsVisible = bool:ExecuteHam(Ham_FVisible, attackerId, victimId);

    if(victimIsVisible)
        return false;

    if(DamagerData[DD_THROUGH_WALLS] == DISABLED)
        return true;

    if((DamagerData[DD_THROUGH_WALLS] == ENABLED) && (PlayerData[attackerId][PD_THROUGH_WALLS] == DISABLED))
        return true;
   
    return false;
}

stock bool:CheckPlayerIsBehindSmoke(const attackerId) {
    if(!ShootsThroughSmoke[attackerId])
        return false;

    if(DamagerData[DD_THROUGH_SMOKE] == DISABLED)
        return true;

    if((DamagerData[DD_THROUGH_SMOKE] == ENABLED) && (PlayerData[attackerId][PD_THROUGH_SMOKE] == DISABLED))
        return true;

    return false;
}

public GetAttackerDamagerColor(const attackerId) {
    new attackerColor = PlayerData[attackerId][PD_COLOR];

    if(PlayerData[attackerId][PD_COLOR] == COLOR_RANDOM)
        attackerColor = random_num(1, charsmax(DamagerColors));

    return attackerColor;
}

public GetVictimDamagerColor(const victimId) {
    new victimColor = PlayerData[victimId][PD_INCOMING_COLOR];

    if(PlayerData[victimId][PD_INCOMING_COLOR] == COLOR_RANDOM)
        victimColor = random_num(1, charsmax(DamagerColors));

    return victimColor;
}

stock ShowHudToPlayer(const playerId, syncObj, color, Float:posX, Float:posY, Float:damage) {
    if(PlayerData[playerId][PD_STATE] == DISABLED)
        return;

    set_hudmessage(DamagerColors[color][1][0], DamagerColors[color][1][1], DamagerColors[color][1][2], posX, posY, 0, 0.1, 2.5, 0.02, 0.02);
    ShowSyncHudMsg(playerId, syncObj, (PlayerData[playerId][PD_STYLE] == STARS) ? "*" : "%.0f", damage);
}

stock bool:FindLineIntersectsSmoke(const Float:vecStart[3], const Float:vecEnd[3]) {
    new smokesNum = ArraySize(ArrayActiveSmokes);

    for(new i, grenadeId, Float:vecSmokeOrigin[3]; i < smokesNum; i++) {
        grenadeId = ArrayGetCell(ArrayActiveSmokes, i);

        get_member(grenadeId, m_Grenade_vSmokeDetonate, vecSmokeOrigin);
        vecSmokeOrigin[2] += DamagerData[DD_SMOKE_RADIUS] - 10.0;

        if(LineIntersectsSmoke(vecStart, vecEnd, vecSmokeOrigin, DamagerData[DD_SMOKE_RADIUS]))
            return true;
    }

    return false;
}

stock bool:LineIntersectsSmoke(const Float:vecStart[3], const Float:vecEnd[3], const Float:vecSmokeOrigin[3], const Float:radius) {
    new Float:vecDir[3];
    xs_vec_sub(vecEnd, vecStart, vecDir);
   
    new Float:vecToCenter[3];
    xs_vec_sub(vecSmokeOrigin, vecStart, vecToCenter);

    new Float:proj = xs_vec_dot(vecDir, vecToCenter) / xs_vec_dot(vecDir, vecDir);
    proj = floatclamp(proj, 0.0, 1.0);

    new Float:vecClosest[3];
    xs_vec_add_scaled(vecStart, vecDir, proj, vecClosest);

    new Float:vecDist[3];
    xs_vec_sub(vecSmokeOrigin, vecClosest, vecDist);

    return bool:(xs_vec_len(vecDist) <= radius);
}
Назад
Верх