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

Mirror Damage (sdkhooks) 1.1rc

neatek

Участник
Сообщения
424
Реакции
226
  • Автор ресурса
  • #1
Mirror Damage (sdkhooks)
Предотвращает дружественный огонь, и возвращает его обратно.

Оригинал

Установка:
положить MirrorDamage.smx в addons/sourcemod/plugins/

Cvars:
sm_mirrordamage_version - Версия плагина
sm_mirrordamage_multiplier - Количество урона возвращаемое обратно атакующему (Def: 0.7)

Требования:
SDKHooks

P.S Загрузить файл не могу на хлмод, так как загрузки не пашут.
 
Последнее редактирование модератором:

BloodyAngel

Участник
Сообщения
72
Реакции
54
C++:
// thx Sheepdude for advice
#pragma semicolon 1
#pragma newdecls required

#include <sourcemod>
#include <sdktools>
#include <sdkhooks>

#define PLUGIN_VERSION "1.1rc"
#define CVAR_FLAGS FCVAR_NOTIFY

ConVar cvar_Enable, cvar_Multiplier, cvar_SlapPlayer, cvar_NoticeFF;
float fMultiplier = 0.0;
bool bEnable = false, bSlapPlayer = false, bNoticeFF = false, bSDKHooked[MAXPLAYERS + 1] = {false, ...};

public Plugin myinfo =
{
    name = "MirrorDamage",
    author = "Neatek",
    description = "Simple plugin for mirror friendlyfire",
    version = PLUGIN_VERSION,
    url = "http://www.neatek.ru/"
};

public void OnPluginStart()
{
    CreateConVar("sm_mirrordamage_version", PLUGIN_VERSION, "Version of MirrorDamage plugin", CVAR_FLAGS|FCVAR_SPONLY|FCVAR_DONTRECORD);
    cvar_Enable = CreateConVar("sm_mirrordamage_enable", "1", "Enable/Disable plugin", CVAR_FLAGS, true, 0.0, true, 1.0);
    cvar_Multiplier = CreateConVar("sm_mirrordamage_multiplier", "0.7", "Amount of damage to inflict to attacker, def 70%", CVAR_FLAGS, true, 0.1);
    cvar_SlapPlayer = CreateConVar("sm_mirrordamage_slap", "0", "Slap attacker?! or just subtraction health", CVAR_FLAGS, true, 0.0, true, 1.0);
    cvar_NoticeFF = CreateConVar("sm_mirrordamage_annonce", "0", "Type in chat about friendlyfire?!", CVAR_FLAGS, true, 0.0, true, 1.0);

    AutoExecConfig(true, "MirrorDamage");

    cvar_Enable.AddChangeHook(OnConVarsChanged);
    cvar_Multiplier.AddChangeHook(OnConVarsChanged);
    cvar_SlapPlayer.AddChangeHook(OnConVarsChanged);
    cvar_NoticeFF.AddChangeHook(OnConVarsChanged);
}

public void OnConfigsExecuted()
{
    OnConVarsChanged(cvar_Enable, "", "");
    OnConVarsChanged(cvar_Multiplier, "", "");
    OnConVarsChanged(cvar_SlapPlayer, "", "");
    OnConVarsChanged(cvar_NoticeFF, "", "");
}

void OnConVarsChanged(ConVar convar, const char[] oValue, const char[] nValue)
{
    if(convar == cvar_Enable)
    {
        bEnable = convar.BoolValue;
        if(bEnable)
        {
            for(int x = 1; x <= MaxClients; x++) // updated, thx Sheepdude
            {
                if(IsClientInGame(x))
                {
                    if(!bSDKHooked[x])
                    {
                        bSDKHooked[x] = true;
                        SDKHook(x, SDKHook_OnTakeDamage, OnTakeDamage);
                    }
                }
            }
        }
        else
        {
            for(int x = 1; x <= MaxClients; x++) // updated, thx Sheepdude
            {
                if(IsClientInGame(x))
                {
                    if(bSDKHooked[x])
                    {
                        bSDKHooked[x] = false;
                        SDKUnhook(x, SDKHook_OnTakeDamage, OnTakeDamage);
                    }
                }
            }
        }
    }
    else if(convar == cvar_Multiplier)
    {
        fMultiplier = convar.FloatValue;
    }
    else if(convar == cvar_SlapPlayer)
    {
        bSlapPlayer = convar.BoolValue;
    }
    else if(convar == cvar_NoticeFF)
    {
        bNoticeFF = convar.BoolValue;
    }
}

public void OnClientPutInServer(int client)
{
    if(bEnable)
    {
        if(client > 0 && !bSDKHooked[client])
        {
            bSDKHooked[client] = true;
            SDKHook(client, SDKHook_OnTakeDamage, OnTakeDamage);
        }
    }
}

public void OnClientDisconnect(int client)
{
    if(client > 0 && bSDKHooked[client])
    {
        bSDKHooked[client] = false;
    }
}

// try to check ;)
Action OnTakeDamage(int client, int &attacker, int &inflictor, float &damage, int &damagetype)
{
    if(!bEnable || !IsClientInGame(client) || !IsClientInGame(attacker) || client == attacker)
    {
        return Plugin_Continue;
    }

    if(GetClientTeam(client) == GetClientTeam(attacker))
    {
        if(damage > 100.0) ForcePlayerSuicide(attacker); // updated, thx Sheepdude
        else
        {
            int mirrordamage = (GetClientHealth(attacker) - RoundFloat(damage * fMultiplier));
            if(mirrordamage < 0) ForcePlayerSuicide(attacker); // updated, thx Sheepdude
            else
            {
                if(!bSlapPlayer)
                {
                    SetEntityHealth(attacker, mirrordamage);
                }
                else
                {
                    SlapPlayer(attacker, mirrordamage, true);
                }
            }
        }

        if(bNoticeFF)
        {
            PrintToChatAll("%N attacked a teammate", attacker);
            return Plugin_Handled;
        }
    }

    return Plugin_Continue;
}
 
Последнее редактирование:

Grey83

не пишу плагины с весны 2022
Сообщения
8,805
Реакции
5,254
@BloodyAngel, фигово написано: если игрок зашёл при выключеном плагине, то для него он не будет работать после включения, пока он не перезайдёт.

И всё, что в OnPluginEnd() можно смело удалять: при выгрузке плагина все его хуки автоматически вырубаются.
То же самое с OnClientDisconnect(): при выходе игрока все повешеные на него хуки удаляются.

Проверка IsClientConnected() не нужна, т.к. IsClientInGame() её в себя включает.
И в циклах по игрокам проверку ValidClient() можно смело менять на просто IsClientInGame(), т.к. все остальные проверки работают вхолостую.
 

BloodyAngel

Участник
Сообщения
72
Реакции
54
@BloodyAngel, фигово написано: если игрок зашёл при выключеном плагине, то для него он не будет работать после включения, пока он не перезайдёт.

И всё, что в OnPluginEnd() можно смело удалять: при выгрузке плагина все его хуки автоматически вырубаются.
То же самое с OnClientDisconnect(): при выходе игрока все повешеные на него хуки удаляются.

Проверка IsClientConnected() не нужна, т.к. IsClientInGame() её в себя включает.
И в циклах по игрокам проверку ValidClient() можно смело менять на просто IsClientInGame(), т.к. все остальные проверки работают вхолостую.
Обновил пост
 

Grey83

не пишу плагины с весны 2022
Сообщения
8,805
Реакции
5,254
в общем я бы сделал вот так (заодно добавил бы квар для возможности блочить урон наносимый союзнику, хотя можно было бы и снижать на какой-нибудь процент):
C-подобный:
#pragma semicolon 1
#pragma newdecls required

#include <sdkhooks>
#include <sdktools_engine>
#include <sdktools_functions>

#define PLUGIN_VERSION "1.1rc"
#define CVAR_FLAGS FCVAR_NOTIFY

static const char
    PL_NAME[]    = "MirrorDamage",
    PL_VER[]    = "1.0.0";

float
    fMultiplier;
bool
    bEnable,
    bSlap,
    bNotice,
    bBlock,
    bHooked[MAXPLAYERS + 1];

public Plugin myinfo =
{
    name        = PL_NAME,
    version        = PL_VER,
    description    = "Simple plugin for mirror friendlyfire",
    author        = "Grey83",
    url            = "https://steamcommunity.com/groups/grey83ds"
}

public void OnPluginStart()
{
    CreateConVar("sm_mirrordamage_version", PLUGIN_VERSION, PL_NAME, FCVAR_DONTRECORD|FCVAR_NOTIFY|FCVAR_SPONLY);

    ConVar cvar;
    cvar = CreateConVar("sm_mirrordamage_enable", "1", "Enable/Disable plugin", CVAR_FLAGS, true, _, true, 1.0);
    cvar.AddChangeHook(CVarChange_Enable);
    CVarChange_Enable(cvar, "", "");

    cvar = CreateConVar("sm_mirrordamage_multiplier", "0.7", "Amount of damage to inflict to attacker, def 70%", CVAR_FLAGS, true, 0.1, true, 10.0);
    cvar.AddChangeHook(CVarChange_Multiplier);
    fMultiplier = cvar.FloatValue;

    cvar = CreateConVar("sm_mirrordamage_slap", "0", "Slap attacker?! or just subtraction health", CVAR_FLAGS, true, _, true, 1.0);
    cvar.AddChangeHook(CVarChange_Slap);
    bSlap = cvar.BoolValue;

    cvar = CreateConVar("sm_mirrordamage_annonce", "0", "Type in chat about friendlyfire?!", CVAR_FLAGS, true, _, true, 1.0);
    cvar.AddChangeHook(CVarChange_Notice);
    bNotice = cvar.BoolValue;

    cvar = CreateConVar("sm_mirrordamage_block", "1", "Block damage to the victim?", CVAR_FLAGS, true, _, true, 1.0);
    cvar.AddChangeHook(CVarChange_Block);
    bBlock = cvar.BoolValue;

    AutoExecConfig(true, "MirrorDamage");
}

public void CVarChange_Enable(ConVar cvar, const char[] oldValue, const char[] newValue)
{
    bool hooked;
    if(hooked == (bEnable = cvar.BoolValue))
        return;

    if((hooked ^= true))
    {
        for(int i; ++i <= MaxClients;) if(IsClientInGame(i)) AddHook(i);
    }
    else
    {
        for(int i; ++i <= MaxClients;) if(bHooked[i])
        {
            bHooked[i] = false;
            SDKUnhook(i, SDKHook_OnTakeDamage, OnTakeDamage);
        }
    }
}

public void CVarChange_Multiplier(ConVar cvar, const char[] oldValue, const char[] newValue)
{
    fMultiplier = cvar.FloatValue;
}

public void CVarChange_Slap(ConVar cvar, const char[] oldValue, const char[] newValue)
{
    bSlap = cvar.BoolValue;
}

public void CVarChange_Notice(ConVar cvar, const char[] oldValue, const char[] newValue)
{
    bNotice = cvar.BoolValue;
}

public void CVarChange_Block(ConVar cvar, const char[] oldValue, const char[] newValue)
{
    bBlock = cvar.BoolValue;
}

public void OnClientPutInServer(int client)
{
    if(bEnable) AddHook(client);
}

void AddHook(int client)
{
    if(!IsFakeClient(client) || (!IsClientReplay(client) && !IsClientSourceTV(client)))
    {
        bHooked[client] = true;
        SDKHook(client, SDKHook_OnTakeDamage, OnTakeDamage);
    }
}

public void OnClientDisconnect(int client)
{
    bHooked[client] = false;
}

Action OnTakeDamage(int client, int &attacker, int &inflictor, float &damage, int &damagetype)
{
    if(!attacker || client == attacker || !IsClientInGame(attacker) || !IsPlayerAlive(attacker)
    || GetClientTeam(client) != GetClientTeam(attacker))
        return Plugin_Continue;

    float dmg = damage * fMultiplier;
    if(bSlap) SlapPlayer(attacker, RoundFloat(dmg));
    else
    {
        static float pos[3];
        GetClientEyePosition(attacker, pos);
        SDKHooks_TakeDamage(attacker, attacker, attacker, dmg, DMG_PLASMA, _, NULL_VECTOR, pos);
    }

    if(bNotice) PrintToChatAll("%N attacked a teammate", attacker);

    if(bBlock)
    {
        damage = 0.0;
        return Plugin_Changed;
    }

    return Plugin_Continue;
}
 

BloodyAngel

Участник
Сообщения
72
Реакции
54
в общем я бы сделал вот так (заодно добавил бы квар для возможности блочить урон наносимый союзнику, хотя можно было бы и снижать на какой-нибудь процент):
C-подобный:
#pragma semicolon 1
#pragma newdecls required

#include <sdkhooks>
#include <sdktools_engine>
#include <sdktools_functions>

#define PLUGIN_VERSION "1.1rc"
#define CVAR_FLAGS FCVAR_NOTIFY

static const char
    PL_NAME[]    = "MirrorDamage",
    PL_VER[]    = "1.0.0";

float
    fMultiplier;
bool
    bEnable,
    bSlap,
    bNotice,
    bBlock,
    bHooked[MAXPLAYERS + 1];

public Plugin myinfo =
{
    name        = PL_NAME,
    version        = PL_VER,
    description    = "Simple plugin for mirror friendlyfire",
    author        = "Grey83",
    url            = "https://steamcommunity.com/groups/grey83ds"
}

public void OnPluginStart()
{
    CreateConVar("sm_mirrordamage_version", PLUGIN_VERSION, PL_NAME, FCVAR_DONTRECORD|FCVAR_NOTIFY|FCVAR_SPONLY);

    ConVar cvar;
    cvar = CreateConVar("sm_mirrordamage_enable", "1", "Enable/Disable plugin", CVAR_FLAGS, true, _, true, 1.0);
    cvar.AddChangeHook(CVarChange_Enable);
    CVarChange_Enable(cvar, "", "");

    cvar = CreateConVar("sm_mirrordamage_multiplier", "0.7", "Amount of damage to inflict to attacker, def 70%", CVAR_FLAGS, true, 0.1, true, 10.0);
    cvar.AddChangeHook(CVarChange_Multiplier);
    fMultiplier = cvar.FloatValue;

    cvar = CreateConVar("sm_mirrordamage_slap", "0", "Slap attacker?! or just subtraction health", CVAR_FLAGS, true, _, true, 1.0);
    cvar.AddChangeHook(CVarChange_Slap);
    bSlap = cvar.BoolValue;

    cvar = CreateConVar("sm_mirrordamage_annonce", "0", "Type in chat about friendlyfire?!", CVAR_FLAGS, true, _, true, 1.0);
    cvar.AddChangeHook(CVarChange_Notice);
    bNotice = cvar.BoolValue;

    cvar = CreateConVar("sm_mirrordamage_block", "1", "Block damage to the victim?", CVAR_FLAGS, true, _, true, 1.0);
    cvar.AddChangeHook(CVarChange_Block);
    bBlock = cvar.BoolValue;

    AutoExecConfig(true, "MirrorDamage");
}

public void CVarChange_Enable(ConVar cvar, const char[] oldValue, const char[] newValue)
{
    bool hooked;
    if(hooked == (bEnable = cvar.BoolValue))
        return;

    if((hooked ^= true))
    {
        for(int i; ++i <= MaxClients;) if(IsClientInGame(i)) AddHook(i);
    }
    else
    {
        for(int i; ++i <= MaxClients;) if(bHooked[i])
        {
            bHooked[i] = false;
            SDKUnhook(i, SDKHook_OnTakeDamage, OnTakeDamage);
        }
    }
}

public void CVarChange_Multiplier(ConVar cvar, const char[] oldValue, const char[] newValue)
{
    fMultiplier = cvar.FloatValue;
}

public void CVarChange_Slap(ConVar cvar, const char[] oldValue, const char[] newValue)
{
    bSlap = cvar.BoolValue;
}

public void CVarChange_Notice(ConVar cvar, const char[] oldValue, const char[] newValue)
{
    bNotice = cvar.BoolValue;
}

public void CVarChange_Block(ConVar cvar, const char[] oldValue, const char[] newValue)
{
    bBlock = cvar.BoolValue;
}

public void OnClientPutInServer(int client)
{
    if(bEnable) AddHook(client);
}

void AddHook(int client)
{
    if(!IsFakeClient(client) || (!IsClientReplay(client) && !IsClientSourceTV(client)))
    {
        bHooked[client] = true;
        SDKHook(client, SDKHook_OnTakeDamage, OnTakeDamage);
    }
}

public void OnClientDisconnect(int client)
{
    bHooked[client] = false;
}

Action OnTakeDamage(int client, int &attacker, int &inflictor, float &damage, int &damagetype)
{
    if(!attacker || client == attacker || !IsClientInGame(attacker) || !IsPlayerAlive(attacker)
    || GetClientTeam(client) != GetClientTeam(attacker))
        return Plugin_Continue;

    float dmg = damage * fMultiplier;
    if(bSlap) SlapPlayer(attacker, RoundFloat(dmg));
    else
    {
        static float pos[3];
        GetClientEyePosition(attacker, pos);
        SDKHooks_TakeDamage(attacker, attacker, attacker, dmg, DMG_PLASMA, _, NULL_VECTOR, pos);
    }

    if(bNotice) PrintToChatAll("%N attacked a teammate", attacker);

    if(bBlock)
    {
        damage = 0.0;
        return Plugin_Changed;
    }

    return Plugin_Continue;
}
На вкус и цвет. Как минимум public в хуках смены переменных уже можно не использовать + у тебя происходит перкуссия из-за того, что ты сначала создаёшь хуки смены переменных, а после загружаешь конфиг, который значения для констант, которые ты следом за хуками запросил запросит заново. К тому же, насколько я знаю, для глобальных констант использующих MAXPLAYERS лучше использовать в данном случае = {false, ...}, дабы стандартное значение выставилось для всех id, ибо, в противном случае, оно выставится только для первого id
 

Grey83

не пишу плагины с весны 2022
Сообщения
8,805
Реакции
5,254
насколько я знаю, для глобальных констант использующих MAXPLAYERS лучше использовать в данном случае = {false, ...}, дабы стандартное значение выставилось для всех id, ибо, в противном случае, оно выставится только для первого id
а доказательство есть или ты только так думаешь?
 

AzureLane

Участник
Сообщения
51
Реакции
32
насколько я знаю, для глобальных констант использующих MAXPLAYERS лучше использовать в данном случае = {false, ...}
Как я помню это важно именно в случае если ты пытаешься установить не стандартное значение, по типу true как в этом случае, в остальных случаях это не обязательно
 

BloodyAngel

Участник
Сообщения
72
Реакции
54
Как я помню это важно именно в случае если ты пытаешься установить не стандартное значение, по типу true как в этом случае, в остальных случаях это не обязательно
Не исключаю, но и со значением false или 0 или 0.0 компилятор порой выдаёт, что требуется выставить в таком формате(warning 241: scalar assignment to array is deprecated; use "{ <val>, ... }" instead).
 

AzureLane

Участник
Сообщения
51
Реакции
32
Не исключаю, но и со значением false или 0 или 0.0 компилятор порой выдаёт, что требуется выставить в таком формате(warning 241: scalar assignment to array is deprecated; use "{ <val>, ... }" instead).
В этом случае просто ничего не указывай, этот варнинг как раз нужно применять в том случае который я написал
 

Grey83

не пишу плагины с весны 2022
Сообщения
8,805
Реакции
5,254
компилятор порой выдаёт, что требуется выставить в таком формате(warning 241: scalar assignment to array is deprecated; use "{ <val>, ... }" instead).
это когда массиву прописываешь значение как единичной переменной
потому и нужно прописывать bool bVariable[MAXPLAYERS+1] = {true, ...};
А раньше (не помню в каких версиях SM) вроде достаточно было просто bool bVariable[MAXPLAYERS+1] = true;
 

BloodyAngel

Участник
Сообщения
72
Реакции
54
это когда массиву прописываешь значение как единичной переменной
потому и нужно прописывать bool bVariable[MAXPLAYERS+1] = {true, ...};
А раньше (не помню в каких версиях SM) вроде достаточно было просто bool bVariable[MAXPLAYERS+1] = true;
В версиях SM ниже 1.11. Сейчас, в новых плагинах я и для false вижу = {false, ...}; в константах использующих [MAXPLAYERS + 1]
 
Сверху Снизу