Breaking Shield

Breaking Shield 1.0.0

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

#include <amxmodx>
#include <fakemeta>
#include <reapi>

#define PLUGIN_NAME        "Breaking Shield"
#define PLUGIN_VERSION    "1.0.0"
#define PLUGIN_AUTHORS    "Albertio & MayroN"

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

#define CONFIG_FILE_PATH "addons/amxmodx/configs/breaking_shield/breaking_shield.ini"

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

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

enum _:ShieldDataStruct {
    Float:STRENGTH,
    Float:PISTOLS_DIVIDER,
    Float:SHOTGUNS_DIVIDER,
    Float:SMGS_DIVIDER,
    Float:RIFLES_DIVIDER,
    Float:SNIPERRIFLES_DIVIDER,
    Float:MACHINEGUNS_DIVIDER,
    Float:GRENADES_DIVIDER,
    GIBS_MODEL[MAX_RESOURCE_PATH_LENGTH],
    NULL_MODEL[MAX_RESOURCE_PATH_LENGTH],
    WORLD_MODEL[MAX_RESOURCE_PATH_LENGTH]
};
new ShieldData[ShieldDataStruct];
new ShieldModels[WeaponIdType][MAX_RESOURCE_PATH_LENGTH];
new ShieldGibsCacheId;

enum _:PlayerDataStruct {
    Float:FIRED_DAMAGE,
    Float:RECEIVED_DAMAGE,
    MODEL_ENTITY
};
new PlayerData[MAX_PLAYERS + 1][PlayerDataStruct];

new Trie:ConfigMap;

new FWD_TraceLine;
new HookChain:HC_PlayerTakeDamage;

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

public plugin_precache() {
    InitConfigMap();
    ParseConfig();
    PrecacheModels();
}

public InitConfigMap() {
    ConfigMap = TrieCreate();
 
    TrieSetCell(ConfigMap, "STRENGTH", STRENGTH);

    TrieSetCell(ConfigMap, "PISTOLS_DIVIDER", PISTOLS_DIVIDER);
    TrieSetCell(ConfigMap, "SHOTGUNS_DIVIDER", SHOTGUNS_DIVIDER);
    TrieSetCell(ConfigMap, "SMGS_DIVIDER", SMGS_DIVIDER);
    TrieSetCell(ConfigMap, "RIFLES_DIVIDER", RIFLES_DIVIDER);
    TrieSetCell(ConfigMap, "SNIPERRIFLES_DIVIDER", SNIPERRIFLES_DIVIDER);
    TrieSetCell(ConfigMap, "MACHINEGUNS_DIVIDER", MACHINEGUNS_DIVIDER);
    TrieSetCell(ConfigMap, "GRENADES_DIVIDER", GRENADES_DIVIDER);

    TrieSetCell(ConfigMap, "GIBS_MODEL", GIBS_MODEL);
    TrieSetCell(ConfigMap, "NULL_MODEL", NULL_MODEL);
    TrieSetCell(ConfigMap, "WORLD_MODEL", WORLD_MODEL);

    TrieSetCell(ConfigMap, "KNIFE_MODEL", WEAPON_KNIFE);
    TrieSetCell(ConfigMap, "HEGRENADE_MODEL", WEAPON_HEGRENADE);
    TrieSetCell(ConfigMap, "FLASHBANG_MODEL", WEAPON_FLASHBANG);
    TrieSetCell(ConfigMap, "SMOKEGRENADE_MODEL", WEAPON_SMOKEGRENADE);
    TrieSetCell(ConfigMap, "DEAGLE_MODEL", WEAPON_DEAGLE);
    TrieSetCell(ConfigMap, "FIVESEVEN_MODEL", WEAPON_FIVESEVEN);
    TrieSetCell(ConfigMap, "GLOCK18_MODEL", WEAPON_GLOCK18);
    TrieSetCell(ConfigMap, "P228_MODEL", WEAPON_P228);
    TrieSetCell(ConfigMap, "USP_MODEL", WEAPON_USP);
}

public ParseConfig() {
    new INIParser:parser = INI_CreateParser();
    INI_SetReaders(parser, "ReadKeyValue", "ReadNewSection");
    INI_ParseFile(parser, CONFIG_FILE_PATH);
    INI_DestroyParser(parser);
}

public PrecacheModels() {
    if(ShieldData[GIBS_MODEL][0] != EOS)
        ShieldGibsCacheId = precache_model(ShieldData[GIBS_MODEL]);

    if(ShieldData[NULL_MODEL][0] != EOS)
        precache_model(ShieldData[NULL_MODEL]);

    if(ShieldData[WORLD_MODEL][0] != EOS)
        precache_model(ShieldData[WORLD_MODEL]);

    for(new i = 1; i < any:WeaponIdType; i++)
        if(ShieldModels[any:i][0] != EOS)
            precache_model(ShieldModels[any:i]);
}

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, "shield")) {
        ParserCurSection = SECTION_SHIELD;
        return true;
    } else if(equal(section, "models")) {
        ParserCurSection = SECTION_MODELS;
        return true;
    }

    return false;
}

public bool:ReadKeyValue(INIParser:parser, const key[], const value[]) {
    new structKey;
    TrieGetCell(ConfigMap, key, structKey);
 
    switch(ParserCurSection) {
        case SECTION_NONE: {
            return false;
        }
        case SECTION_SHIELD: {
            ShieldData[structKey] = any:str_to_float(value);
        }
        case SECTION_MODELS: {
            if(value[0] == EOS)
                return true;

            if(equal(key, "GIBS_MODEL") || equal(key, "NULL_MODEL") || equal(key, "WORLD_MODEL")) {
                copy(ShieldData[any:structKey], MAX_RESOURCE_PATH_LENGTH - 1, value);
            } else {
                copy(ShieldModels[WeaponIdType:structKey], MAX_RESOURCE_PATH_LENGTH - 1, value);
            }
        }
    }

    return true;
}

public plugin_init() {
    register_plugin(PLUGIN_NAME, PLUGIN_VERSION, PLUGIN_AUTHORS);

    RegisterHookChain(RG_CBasePlayer_Killed, "Player_Killed_Post", true);

    RegisterHookChain(RG_CBasePlayerWeapon_DefaultDeploy, "PlayerWeapon_DefaultDeploy_Post", true);

    RegisterHookChain(RG_CBasePlayer_GiveShield, "Player_GiveShield_Pre", false);
    RegisterHookChain(RG_CBasePlayer_DropShield, "Player_DropShield_Post", true);
 
    RegisterHookChain(RG_CBaseEntity_FireBuckshots, "Entity_FireBuckshots_Pre", false);
    RegisterHookChain(RG_CBaseEntity_FireBullets3, "Entity_FireBullets3_Pre", false);

    RegisterHookChain(RG_CBaseEntity_FireBuckshots, "Entity_Fire_Post", true);
    RegisterHookChain(RG_CBaseEntity_FireBullets3, "Entity_Fire_Post", true);

    RegisterHookChain(RG_CGrenade_ExplodeHeGrenade, "Grenade_ExplodeHeGrenade_Pre", false);
 
    HC_PlayerTakeDamage = RegisterHookChain(RG_CBasePlayer_TakeDamage, "Player_TakeDamage_Post", true);
    DisableHookChain(HC_PlayerTakeDamage);
}

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

public client_disconnected(playerId) {
    RemovePlayerModelEntity(playerId);

    arrayset(PlayerData[playerId], 0, sizeof(PlayerData[]));
}

public Player_Killed_Post(const victimId) {
    RemovePlayerModelEntity(victimId);
}

public PlayerWeapon_DefaultDeploy_Post(const weaponId) {
    new playerId = get_member(weaponId, m_pPlayer);

    if(!is_user_alive(playerId))
        return;

    if(!bool:get_member(playerId, m_bOwnsShield)) {
        RemovePlayerModelEntity(playerId);
        return;
    }

    SetShieldModel(playerId);
    SetShieldSubModel(PlayerData[playerId][MODEL_ENTITY], PlayerData[playerId][RECEIVED_DAMAGE]);
}

public Player_GiveShield_Pre(const playerId) {
    new shieldId = FindNearestShield(playerId);

    if(is_nullent(shieldId))
        return;

    PlayerData[playerId][RECEIVED_DAMAGE] = GetDmgReceivedToShield(shieldId);
    SetDmgReceivedToShield(shieldId, 0.0);
}

public Player_DropShield_Post(const playerId) {
    RemovePlayerModelEntity(playerId);
 
    new shieldId = FindDroppedShield();
 
    if(is_nullent(shieldId))
        return;

    SetShieldModel(shieldId);
    SetShieldSubModel(shieldId, PlayerData[playerId][RECEIVED_DAMAGE]);

    SetDmgReceivedToShield(shieldId, PlayerData[playerId][RECEIVED_DAMAGE]);
    PlayerData[playerId][RECEIVED_DAMAGE] = 0.0;
}

public Entity_FireBuckshots_Pre(
    entId,
    shots,
    Float:vecSrc[3],
    Float:vecDir[3],
    Float:vecSpread[3],
    Float:distance,
    tracerFreq,
    damage,
    attackerId
) {
    WriteTraceData(attackerId, damage);
}

public Entity_FireBullets3_Pre(
    entId,
    Float:vecSrc[3],
    Float:vecDir[3],
    Float:vecSpread,
    Float:distance,
    penetration,
    bulletType,
    damage,
    Float:rangeModifier,
    attackerId
) {
    WriteTraceData(attackerId, damage);
}

public Entity_Fire_Post() {
    unregister_forward(FM_TraceLine, FWD_TraceLine, true);
}

public Grenade_ExplodeHeGrenade_Pre(const grenadeId) {
    if(is_nullent(grenadeId))
        return;

    new Float:vecGrenadeOrigin[3], Float:grenadeDamage;
    get_entvar(grenadeId, var_origin, vecGrenadeOrigin);
    get_entvar(grenadeId, var_dmg, grenadeDamage);

    ApplyDamageToShieldInRadius(vecGrenadeOrigin, grenadeDamage, grenadeDamage / ShieldData[GRENADES_DIVIDER]);
 
    EnableHookChain(HC_PlayerTakeDamage);
}

public Player_TakeDamage_Post(const victimId, inflictorId, attackerId, Float:damage, bitsDamageType) {
    DisableHookChain(HC_PlayerTakeDamage);
 
    if(~bitsDamageType & DMG_GRENADE)
        return;

    if(!FloatNearlyEqual(damage, 0.0))
        return;
 
    if(!is_user_alive(victimId) || !rg_is_player_can_takedamage(victimId, attackerId))
        return;

    if(!bool:get_member(victimId, m_bOwnsShield))
        return;

    ApplyDamageToPlayerShield(victimId, 0, damage / ShieldData[GRENADES_DIVIDER]);
}

public TraceLine_Post(Float:vecStart[3], Float:vecEnd[3], ignoreMonsters, attackerId, traceLine) {
    if(ApplyDamageToPlayerShield(NULLENT, traceLine, PlayerData[attackerId][FIRED_DAMAGE]))
        return;

    ApplyDamageToShieldOnGround(vecStart, NULLENT, traceLine, PlayerData[attackerId][FIRED_DAMAGE]);
}

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

stock WriteTraceData(const attackerId, damage) {
    if(!is_user_alive(attackerId))
        return;
 
    new weaponId = get_member(attackerId, m_pActiveItem);
 
    if(is_nullent(weaponId))
        return;
 
    new bitsWeaponType = (1<<any:get_member(weaponId, m_iId));

    new Float:damageDivider;

    if(CSW_ALL_PISTOLS & bitsWeaponType) {
        damageDivider = ShieldData[PISTOLS_DIVIDER];
    } else if(CSW_ALL_SHOTGUNS & bitsWeaponType) {
        damageDivider = ShieldData[SHOTGUNS_DIVIDER];
    } else if(CSW_ALL_SMGS & bitsWeaponType) {
        damageDivider = ShieldData[SMGS_DIVIDER];
    } else if(CSW_ALL_RIFLES & bitsWeaponType) {
        damageDivider = ShieldData[RIFLES_DIVIDER];
    } else if(CSW_ALL_SNIPERRIFLES & bitsWeaponType) {
        damageDivider = ShieldData[SNIPERRIFLES_DIVIDER];
    } else if(CSW_ALL_MACHINEGUNS & bitsWeaponType) {
        damageDivider = ShieldData[MACHINEGUNS_DIVIDER];
    }

    PlayerData[attackerId][FIRED_DAMAGE] = float(damage) / damageDivider;

    FWD_TraceLine = register_forward(FM_TraceLine, "TraceLine_Post", true);
}

stock ApplyDamageToShieldInRadius(const Float:vecGrenadeOrigin[3], const Float:radius, const Float:damage) {
    new entId = NULLENT;

    while((entId = engfunc(EngFunc_FindEntityInSphere, entId, vecGrenadeOrigin, radius)) > 0) {
        if(!FClassnameIs(entId, "weapon_shield"))
            continue;

        ApplyDamageToShieldOnGround(NULL_VECTOR, entId, 0, damage);
    }
}

stock bool:ApplyDamageToShieldOnGround(const Float:vecStart[3], entId, const traceLine, const Float:damage) {
    if(is_nullent(entId)) {
        new Float:vecEnd2[3];
        get_tr2(traceLine, TR_vecEndPos, vecEnd2);
 
        entId = FindAttackedShieldOnGround(vecStart, vecEnd2);
    }

    if(is_nullent(entId))
        return false;

    new Float:dmgReceived = GetDmgReceivedToShield(entId) + damage;

    if(dmgReceived > ShieldData[STRENGTH]) {
        if(ShieldData[GIBS_MODEL][0] != EOS)
            MakeShieldGibs(entId, ShieldGibsCacheId);

        rg_remove_entity(entId);
    } else {
        SetDmgReceivedToShield(entId, dmgReceived);
        SetShieldSubModel(entId, dmgReceived);
    }

    return true;
}

stock bool:ApplyDamageToPlayerShield(victimId, const traceLine, const Float:damage) {
    if(is_nullent(victimId)) {
        if(HitBoxGroup:get_tr2(traceLine, TR_iHitgroup) != HITGROUP_SHIELD)
            return false;

        victimId = get_tr2(traceLine, TR_pHit);
    }

    if(!is_user_alive(victimId))
        return false;

    PlayerData[victimId][RECEIVED_DAMAGE] += damage;

    if(PlayerData[victimId][RECEIVED_DAMAGE] > ShieldData[STRENGTH]) {
        PlayerData[victimId][RECEIVED_DAMAGE] = 0.0;

        if(ShieldData[GIBS_MODEL][0] != EOS)
            MakeShieldGibs(victimId, ShieldGibsCacheId);
    
        RemovePlayerModelEntity(victimId);
        rg_remove_item(victimId, "weapon_shield");
    } else {
        SetShieldSubModel(PlayerData[victimId][MODEL_ENTITY], PlayerData[victimId][RECEIVED_DAMAGE]);
    }

    return true;
}

stock SetDmgReceivedToShield(const shieldId, const Float:dmgReceived) {
    set_entvar(shieldId, var_dmg_take, FloatNearlyEqual(dmgReceived, 0.0) ? -1.0 : dmgReceived);
}

stock Float:GetDmgReceivedToShield(const shieldId) {
    new Float:dmgReceived = Float:get_entvar(shieldId, var_dmg_take);

    return (dmgReceived == -1.0) ? 0.0 : dmgReceived;
}

stock FindNearestShield(const playerId) {
    new nearestEntId = NULLENT, entId = NULLENT;
    new Float:dist, Float:nearestDist = 8192.0;
    new Float:vecPlOrigin[3], Float:vecEntOrigin[3];
    get_entvar(playerId, var_origin, vecPlOrigin);
 
    while((entId = engfunc(EngFunc_FindEntityByString, entId, "classname", "weapon_shield")) > 0) {
        get_entvar(entId, var_origin, vecEntOrigin);
        dist = get_distance_f(vecPlOrigin, vecEntOrigin);

        if(dist < nearestDist) {
            nearestEntId = entId;
            nearestDist = dist;
        }
    }

    return nearestEntId;
}

stock FindDroppedShield() {
    new entId = NULLENT;
 
    while((entId = engfunc(EngFunc_FindEntityByString, entId, "classname", "weapon_shield")) > 0)
        if(FloatNearlyEqual(Float:get_entvar(entId, var_dmg_take), 0.0))
            break;

    return entId;
}

stock FindAttackedShieldOnGround(const Float:vecStart[3], const Float:vecEnd[3]) {
    new entId = NULLENT;

    while((entId = engfunc(EngFunc_FindEntityByString, entId, "classname", "weapon_shield")) > 0) {
        new traceModel = create_tr2();
        engfunc(EngFunc_TraceModel, vecStart, vecEnd, HULL_POINT, entId, traceModel);

        new hitEnt = get_tr2(traceModel, TR_pHit);
        free_tr2(traceModel);

        if(hitEnt != entId || is_nullent(entId))
            continue;

        return entId;
    }

    return NULLENT;
}

stock SetShieldModel(const entId) {
    if(is_nullent(entId))
        return;
 
    if(entId >= 1 && entId <= MaxClients) {
        new weaponId = get_member(entId, m_pActiveItem);

        if(is_nullent(weaponId))
            return;

        new WeaponIdType:weaponType = WeaponIdType:get_member(weaponId, m_iId);

        if(ShieldModels[weaponType][0] != EOS)
            SetPlayerModel(entId, ShieldModels[weaponType], Float:{0.0, 13.0});
    } else if(ShieldData[WORLD_MODEL] != EOS) {
        engfunc(EngFunc_SetModel, entId, ShieldData[WORLD_MODEL]);
    }
}

stock SetShieldSubModel(const entId, Float:dmgReceived) {
    if(is_nullent(entId))
        return;
 
    dmgReceived = 100.0 / (ShieldData[STRENGTH] / dmgReceived);
 
    if(dmgReceived > 66.66) {
        set_entvar(entId, var_body, 2);
    } else if(dmgReceived > 33.33) {
        set_entvar(entId, var_body, 1);
    } else if(dmgReceived > 0.0) {
        set_entvar(entId, var_body, 0);
    }
}

stock bool:SetPlayerModel(const playerId, const model[], const Float:attachment[2]) {
    if(is_nullent(PlayerData[playerId][MODEL_ENTITY]))
        if(!CreatePlayerModelEntity(playerId))
            return;

    new entId = PlayerData[playerId][MODEL_ENTITY];

    engfunc(EngFunc_SetModel, entId, model);

    set_entvar(entId, var_frame, 0.0);
    set_entvar(entId, var_framerate, 1.0);
    set_entvar(entId, var_animtime, get_gametime());

    if(ShieldData[NULL_MODEL] != EOS)
        set_entvar(playerId, var_weaponmodel, ShieldData[NULL_MODEL]);

    MoveController(playerId, 0, attachment[0], Float:{-25.0, 25.0});
    MoveController(playerId, 1, attachment[1], Float:{-25.0, 25.0});
}

stock bool:CreatePlayerModelEntity(const playerId) {
    new entId = rg_create_entity("info_target");

    if(!is_nullent(entId)) {
        PlayerData[playerId][MODEL_ENTITY] = entId;

        set_entvar(entId, var_classname, "ent_weapon_pmodel");
        set_entvar(entId, var_movetype, MOVETYPE_FOLLOW);
        set_entvar(entId, var_owner, playerId);
        set_entvar(entId, var_aiment, playerId);

        return true;
    }

    return false;
}

stock RemovePlayerModelEntity(const playerId) {
    new entId = PlayerData[playerId][MODEL_ENTITY];
    PlayerData[playerId][MODEL_ENTITY] = NULLENT;

    if(!is_nullent(entId)) {
        set_entvar(entId, var_flags, FL_KILLME);
        set_entvar(entId, var_nextthink, get_gametime());
    }
}

stock MoveController(const entId, const controller, Float:value, const Float:minMaxValue[2]) {
    if(is_nullent(entId))
        return;

    value = floatclamp(value, minMaxValue[0], minMaxValue[1]);

    new Float:length = floatabs(minMaxValue[0]) + minMaxValue[1];
    value = ((length / 2.0 + value) / length) * 255.0;

    set_entvar(entId, var_controller, floatround(value), controller);
}

stock MakeShieldGibs(const entId, const cacheId) {
    new Float:vecEntOrigin[3];
    get_entvar(entId, var_origin, vecEntOrigin);

    message_begin_f(MSG_PAS, SVC_TEMPENTITY, vecEntOrigin);
    write_byte(TE_BREAKMODEL);
    write_coord_f(vecEntOrigin[0]);
    write_coord_f(vecEntOrigin[1]);
    write_coord_f(vecEntOrigin[2]);
    write_coord(16);
    write_coord(16);
    write_coord(16);
    write_coord(random_num(-50, 50));
    write_coord(random_num(-50, 50));
    write_coord(25);
    write_byte(10);
    write_short(cacheId);
    write_byte(10);
    write_byte(25);
    write_byte(BREAK_METAL);
    message_end();
}

stock bool:FloatNearlyEqual(Float:value1, Float:value2) {
    return bool:((value1 == value2) || (floatabs(value1 - value2) < 0.001));
}
Назад
Верх