Склад полезного кода [GoldSrc]

Сообщения
494
Реакции
340
Помог
11 раз(а)
Деление целых чисел с остатком.(Просто для удобства)
#define mod(%0,%1) ( %0 % %1 )
Приведение простой операции к функции != удобство.
8 Янв 2023
Деление вещественных чисел с остатком.
C++:
stock Float: fmod( Float: flNumerator, Float: flDenominator )
{
if ( flDenominator == 0.0 )
set_fail_state( "Trying to divide by 0" );

return flNumerator - ( floatround( flNumerator / flDenominator, floatround_tozero ) * flDenominator );
}
Я понимаю, что деление на 0 может уничтожить мир, но достаточно ретёрна с логом ошибки без отключения плагина.
 
Сообщения
519
Реакции
458
Предупреждения
17
Помог
8 раз(а)
bizon, Откуда то он мог знать? Похоже он откопал код из 2006 😂
 
Сообщения
392
Реакции
283
Помог
3 раз(а)
Кастомный урон по радиусу с возможностью указывать разные функции зависимости урона от расстояния и всякими другими фичами)

C++:
#include <amxmodx>
#include <fakemeta>
#include <hamsandwich>
#include <reapi>
#include <xs>

enum RadiusDamage_Func {
    /**
     * На любом расстоянии урон будет максимальным.
     *
     * fFuncVar определяет множитель урона на любом расстоянии.
     * По умолчанию = 1.0
     */
    RadiusDamage_Static,

    /**
     * Урон будет линейно зависеть от расстояния.
     * Т.е. на сколько дальше, на столько меньше урона.
     *
     * fFuncVar определяет множитель параметра функции.
     * По умолчанию = 1.0
     */
    RadiusDamage_Linear,
 
    /**
     * Расстояние возводится в степень.
     * Ближе к центру урон падает медленнее.
     *
     * fFuncVar определяет показатель степени.
     * По умолчанию = 2.0
     */
    RadiusDamage_Sqr,
 
    /**
     * Берётся корень от расстояния.
     * Ближе к центру урон падает быстрее.
     *
     * fFuncVar определяет показатель корня.
     * По умолчанию = 2.0
     */
    RadiusDamage_Sqrt,
 
    /**
     * Дальше от центра урон падает быстрее.
     */
    RadiusDamage_Sin,
 
    /**
     * Ближе к середине радиуса урон падает медленнее.
     * На самом деле, получается близко к линейному.
     */
    RadiusDamage_Tan,
 
    /**
     * От центра сначала падает быстрее, потом замедляется.
     * На середине радиуса совпадает с линейной.
     */
    RadiusDamage_Arcsin,
}

enum RadiusDamage_InnerRadiusBehavior {
    /**
     * Расстояние считается от внутреннего радиуса, а не от центра.
     */
    RadiusDamage_OffsetX,

    /**
     * Множитель урона вычисляется от фактического расстояния + внутреннего радиуса, но не больше общего радиуса.
     */
    RadiusDamage_OffsetFx,

    /**
     * Если игрок вне внутреннего радиуса, множитель урона вычисляется от фактического расстояния.
     */
    RadiusDamage_Overlay,
}

/**
* Наносит урон игрокам в указанном радиусе
*
* @param fvOrigin Источник урона
* @param InflictorId Индекс сущности, нанёсшей урон
* @param AttackerId Индекс сущности, инициировавшей нанесение урона
* @param fBaseDamage Базовое значение урона (впритык в источнику)
* @param fRadius Радиус, в котором будет нанесён урон
* @param iClassIgnore Класс сущностей, которым урон не будет нанесён (см. константы CLASS_)
* @param bitsDamageType Тип наносимого урона (см. константы DMG_)
* @param iFunc Функция, для вычисления урона в зависимости от расстояния (см. RadiusDamage_Func)
* @param fFuncVar Дополнительный параметр функции
* @param fInnerRadius Значение внутреннего радиуса, в котором игрок получит максимальный урон
* @param iInnerRadiusBehavior Определяет механику работы внутреннего радиуса (см. RadiusDamage_InnerRadiusBehavior)
* @param iIgnoreEntity Индекс сущности, которой крон не будет нанесён
* @param bCalcFromHitbox Если true - будет считать расстояние от края хитбокса, иначе от центра
* @param bThroughWalls Должен ли наноситься урон через стены
*
* @noreturn
*/
RadiusDamage(
    const Float:fvOrigin[3],
    const InflictorId,
    const AttackerId,
    const Float:fBaseDamage,
    const Float:fRadius,
    const iClassIgnore = CLASS_NONE,
    const bitsDamageType = DMG_GENERIC,

    // Additional parameters
    const RadiusDamage_Func:iFunc = RadiusDamage_Linear,
    const Float:fFuncVar = 0.0,

    const Float:fInnerRadius = 0.0,
    const RadiusDamage_InnerRadiusBehavior:iInnerRadiusBehavior = RadiusDamage_OffsetX,

    const iIgnoreEntity = 0,

    const bool:bCalcFromHitbox = false,
    const bool:bThroughWalls = false
) {
    new EntId = -1;
    new const Float:fInnerRadiusPercent = fInnerRadius / fRadius;

    while ((EntId = engfunc(EngFunc_FindEntityInSphere, EntId, fvOrigin, fRadius)) != 0) {
        if (EntId == iIgnoreEntity) {
            continue;
        }

        if (get_entvar(EntId, var_takedamage) == DAMAGE_NO) {
            continue;
        }

        if (iClassIgnore && ExecuteHamB(Ham_Classify, EntId) == iClassIgnore) {
            continue;
        }
     
        if (FClassnameIs(EntId, "player") && !rg_is_player_can_takedamage(EntId, AttackerId)) {
            continue;
        }

        new Float:fvEntOrigin[3];
        RadiusDamage_GetEntCenter(EntId, fvEntOrigin);

        new iTrace = create_tr2();
        engfunc(EngFunc_TraceLine, fvOrigin, fvEntOrigin, DONT_IGNORE_MONSTERS, FM_NULLENT, iTrace);

        new Float:fFraction;
        get_tr2(iTrace, TR_flFraction, fFraction);
        new iTracedEnt = get_tr2(iTrace, TR_pHit);

        if (!bThroughWalls && iTracedEnt != EntId && fFraction != 1.0) {
            continue;
        }

        if (bCalcFromHitbox) {
            get_tr2(iTrace, TR_vecEndPos, fvEntOrigin);
        }

        new Float:fDistance = xs_vec_distance(fvOrigin, fvEntOrigin);
     
        new Float:fDmgMult;
        if (iInnerRadiusBehavior == RadiusDamage_Overlay && fDistance <= fInnerRadius) {
            fDmgMult = 1.0;
        } else {
            new Float:fDistancePercent;
            if (iInnerRadiusBehavior == RadiusDamage_OffsetX) {
                fDistancePercent = 1.0 - floatclamp(((fDistance - fInnerRadius) / (fRadius - fInnerRadius)), 0.0, 1.0);
            } else {
                fDistancePercent = 1.0 - floatmin((fDistance / fRadius), 1.0);
            }

            fDmgMult = RadiusDamage_CalcDamage(iFunc, fDistancePercent, fFuncVar);

            if (iInnerRadiusBehavior == RadiusDamage_OffsetFx) {
                fDmgMult = floatmin(fDmgMult + fInnerRadiusPercent, 1.0);
            }
        }

        if (fFraction == 1.0 || iTracedEnt != EntId) {
            ExecuteHamB(Ham_TakeDamage, EntId, InflictorId, AttackerId, fBaseDamage * fDmgMult, bitsDamageType);
        } else {
            new Float:fvTraceDirection[3];
            xs_vec_sub(fvEntOrigin, fvOrigin, fvTraceDirection);
            xs_vec_normalize(fvTraceDirection, fvTraceDirection);
         
            rg_multidmg_clear();
            ExecuteHamB(Ham_TraceAttack, EntId, InflictorId, fBaseDamage * fDmgMult, fvTraceDirection, iTrace, bitsDamageType);
            rg_multidmg_apply(InflictorId, AttackerId);
        }

        free_tr2(iTrace);
    }
}

RadiusDamage_GetEntCenter(const EntId, Float:fvCenter[3]) {
    if (FClassnameIs(EntId, "func_breakable")) {
        new Float:fvAbsMin[3], Float:fvSize[3];
        get_entvar(EntId, var_absmin, fvAbsMin);
        get_entvar(EntId, var_size, fvSize);
        xs_vec_div_scalar(fvSize, 2.0, fvSize);
        xs_vec_add(fvAbsMin, fvSize, fvCenter);
    } else {
        get_entvar(EntId, var_origin, fvCenter);
    }
}

Float:RadiusDamage_CalcDamage(const RadiusDamage_Func:iFunc, const Float:fX, const Float:fFuncVar = 0.0) {
    new Float:fVar = fFuncVar;
    if (fVar == 0.0) {
        switch (iFunc) {
            case RadiusDamage_Sqr, RadiusDamage_Sqrt:
                fVar = 2.0;
            case RadiusDamage_Linear, RadiusDamage_Static:
                fVar = 1.0;
            // Для остальных не используется
        }
    }
 
    new Float:fRes;
    switch (iFunc) {
        case RadiusDamage_Static:
            fRes = fVar;
        case RadiusDamage_Linear:
            fRes = fX * fVar;
        case RadiusDamage_Sqr:
            fRes = floatpower(fX, fVar);
        case RadiusDamage_Sqrt:
            fRes = floatpower(fX, 1 / fVar);

        // Эти числа подобраны тупым перебором,
        // чтобы значения функций влезали в диапазон [0.0; 1.0] при 0.0 < fX < 1.0
        case RadiusDamage_Sin:
            fRes = floatsin(fX * 1.57, radian);
        case RadiusDamage_Tan:
            fRes = floattan(fX * 0.7854, radian);
        case RadiusDamage_Arcsin:
            fRes = (floatasin((fX - 0.5) * 2, radian) + 1.5) / 3;
    }

    return floatclamp(fRes, 0.0, 1.0);
}
1680440456095.png
C++:
#include <amxmodx>
#include <fakemeta>
#include <hamsandwich>
#include <reapi>
#include <xs>

enum RadiusDamage_Func {
    /**
     * На любом расстоянии урон будет максимальным.
     *
     * fFuncVar определяет множитель урона на любом расстоянии.
     * По умолчанию = 1.0
     */
    RadiusDamage_Static,

    /**
     * Урон будет линейно зависеть от расстояния.
     * Т.е. на сколько дальше, на столько меньше урона.
     *
     * fFuncVar определяет множитель параметра функции.
     * По умолчанию = 1.0
     */
    RadiusDamage_Linear,
 
    /**
     * Расстояние возводится в степень.
     * Ближе к центру урон падает медленнее.
     *
     * fFuncVar определяет показатель степени.
     * По умолчанию = 2.0
     */
    RadiusDamage_Sqr,
 
    /**
     * Берётся корень от расстояния.
     * Ближе к центру урон падает быстрее.
     *
     * fFuncVar определяет показатель корня.
     * По умолчанию = 2.0
     */
    RadiusDamage_Sqrt,
 
    /**
     * Дальше от центра урон падает быстрее.
     */
    RadiusDamage_Sin,
 
    /**
     * Ближе к середине радиуса урон падает медленнее.
     * На самом деле, получается близко к линейному.
     */
    RadiusDamage_Tan,
 
    /**
     * От центра сначала падает быстрее, потом замедляется.
     * На середине радиуса совпадает с линейной.
     */
    RadiusDamage_Arcsin,
}

enum RadiusDamage_InnerRadiusBehavior {
    /**
     * Расстояние считается от внутреннего радиуса, а не от центра.
     */
    RadiusDamage_OffsetX,

    /**
     * Множитель урона вычисляется от фактического расстояния + внутреннего радиуса, но не больше общего радиуса.
     */
    RadiusDamage_OffsetFx,

    /**
     * Если игрок вне внутреннего радиуса, множитель урона вычисляется от фактического расстояния.
     */
    RadiusDamage_Overlay,
}

public plugin_init() {
    register_clcmd("radiusdmg", "@Cmd_RadiusDmg");
}

@Cmd_RadiusDmg(const UserId) {
    new Float:fvOrigin[3];
    get_entvar(UserId, var_origin, fvOrigin);

    new RadiusDamage_Func:iFunc = RadiusDamage_Linear;
    if (read_argc() >= 2) {
        iFunc = RadiusDamage_Func:read_argv_int(1);
    }

    RadiusDamage(
        fvOrigin, UserId, UserId, 1000.0, 500.0,
        .fInnerRadius=100.0, .iInnerRadiusBehavior=RadiusDamage_OffsetX,
        .iFunc=iFunc, .fFuncVar=0.0,
        .iIgnoreEntity=UserId,
        .bCalcFromHitbox=true,
        .bThroughWalls=true
    );
}

/**
* Наносит урон игрокам в указанном радиусе
*
* @param fvOrigin Источник урона
* @param InflictorId Индекс сущности, нанёсшей урон
* @param AttackerId Индекс сущности, инициировавшей нанесение урона
* @param fBaseDamage Базовое значение урона (впритык в источнику)
* @param fRadius Радиус, в котором будет нанесён урон
* @param iClassIgnore Класс сущностей, которым урон не будет нанесён (см. константы CLASS_)
* @param bitsDamageType Тип наносимого урона (см. константы DMG_)
* @param iFunc Функция, для вычисления урона в зависимости от расстояния (см. RadiusDamage_Func)
* @param fFuncVar Дополнительный параметр функции
* @param fInnerRadius Значение внутреннего радиуса, в котором игрок получит максимальный урон
* @param iInnerRadiusBehavior Определяет механику работы внутреннего радиуса (см. RadiusDamage_InnerRadiusBehavior)
* @param iIgnoreEntity Индекс сущности, которой крон не будет нанесён
* @param bCalcFromHitbox Если true - будет считать расстояние от края хитбокса, иначе от центра
* @param bThroughWalls Должен ли наноситься урон через стены
*
* @noreturn
*/
RadiusDamage(
    const Float:fvOrigin[3],
    const InflictorId,
    const AttackerId,
    const Float:fBaseDamage,
    const Float:fRadius,
    const iClassIgnore = CLASS_NONE,
    const bitsDamageType = DMG_GENERIC,

    // Additional parameters
    const RadiusDamage_Func:iFunc = RadiusDamage_Linear,
    const Float:fFuncVar = 0.0,

    const Float:fInnerRadius = 0.0,
    const RadiusDamage_InnerRadiusBehavior:iInnerRadiusBehavior = RadiusDamage_OffsetX,

    const iIgnoreEntity = 0,

    const bool:bCalcFromHitbox = false,
    const bool:bThroughWalls = false
) {
    new EntId = -1;
    new const Float:fInnerRadiusPercent = fInnerRadius / fRadius;

    while ((EntId = engfunc(EngFunc_FindEntityInSphere, EntId, fvOrigin, fRadius)) != 0) {
        if (EntId == iIgnoreEntity) {
            continue;
        }

        if (get_entvar(EntId, var_takedamage) == DAMAGE_NO) {
            continue;
        }

        if (iClassIgnore && ExecuteHamB(Ham_Classify, EntId) == iClassIgnore) {
            continue;
        }
     
        if (FClassnameIs(EntId, "player") && !rg_is_player_can_takedamage(EntId, AttackerId)) {
            continue;
        }

        new Float:fvEntOrigin[3];
        RadiusDamage_GetEntCenter(EntId, fvEntOrigin);

        new iTrace = create_tr2();
        engfunc(EngFunc_TraceLine, fvOrigin, fvEntOrigin, DONT_IGNORE_MONSTERS, FM_NULLENT, iTrace);

        new Float:fFraction;
        get_tr2(iTrace, TR_flFraction, fFraction);
        new iTracedEnt = get_tr2(iTrace, TR_pHit);

        if (!bThroughWalls && iTracedEnt != EntId && fFraction != 1.0) {
            continue;
        }

        if (bCalcFromHitbox) {
            get_tr2(iTrace, TR_vecEndPos, fvEntOrigin);
        }

        new Float:fDistance = xs_vec_distance(fvOrigin, fvEntOrigin);
     
        new Float:fDmgMult;
        if (iInnerRadiusBehavior == RadiusDamage_Overlay && fDistance <= fInnerRadius) {
            fDmgMult = 1.0;
        } else {
            new Float:fDistancePercent;
            if (iInnerRadiusBehavior == RadiusDamage_OffsetX) {
                fDistancePercent = 1.0 - floatclamp(((fDistance - fInnerRadius) / (fRadius - fInnerRadius)), 0.0, 1.0);
            } else {
                fDistancePercent = 1.0 - floatmin((fDistance / fRadius), 1.0);
            }

            fDmgMult = RadiusDamage_CalcDamage(iFunc, fDistancePercent, fFuncVar);

            if (iInnerRadiusBehavior == RadiusDamage_OffsetFx) {
                fDmgMult = floatmin(fDmgMult + fInnerRadiusPercent, 1.0);
            }
        }

        if (fFraction == 1.0 || iTracedEnt != EntId) {
            ExecuteHamB(Ham_TakeDamage, EntId, InflictorId, AttackerId, fBaseDamage * fDmgMult, bitsDamageType);
        } else {
            new Float:fvTraceDirection[3];
            xs_vec_sub(fvEntOrigin, fvOrigin, fvTraceDirection);
            xs_vec_normalize(fvTraceDirection, fvTraceDirection);
         
            rg_multidmg_clear();
            ExecuteHamB(Ham_TraceAttack, EntId, InflictorId, fBaseDamage * fDmgMult, fvTraceDirection, iTrace, bitsDamageType);
            rg_multidmg_apply(InflictorId, AttackerId);
        }

        free_tr2(iTrace);
    }
}

RadiusDamage_GetEntCenter(const EntId, Float:fvCenter[3]) {
    if (FClassnameIs(EntId, "func_breakable")) {
        new Float:fvAbsMin[3], Float:fvSize[3];
        get_entvar(EntId, var_absmin, fvAbsMin);
        get_entvar(EntId, var_size, fvSize);
        xs_vec_div_scalar(fvSize, 2.0, fvSize);
        xs_vec_add(fvAbsMin, fvSize, fvCenter);
    } else {
        get_entvar(EntId, var_origin, fvCenter);
    }
}

Float:RadiusDamage_CalcDamage(const RadiusDamage_Func:iFunc, const Float:fX, const Float:fFuncVar = 0.0) {
    new Float:fVar = fFuncVar;
    if (fVar == 0.0) {
        switch (iFunc) {
            case RadiusDamage_Sqr, RadiusDamage_Sqrt:
                fVar = 2.0;
            case RadiusDamage_Linear, RadiusDamage_Static:
                fVar = 1.0;
            // Для остальных не используется
        }
    }
 
    new Float:fRes;
    switch (iFunc) {
        case RadiusDamage_Static:
            fRes = fVar;
        case RadiusDamage_Linear:
            fRes = fX * fVar;
        case RadiusDamage_Sqr:
            fRes = floatpower(fX, fVar);
        case RadiusDamage_Sqrt:
            fRes = floatpower(fX, 1 / fVar);

        // Эти числа подобраны тупым перебором,
        // чтобы значения функций влезали в диапазон [0.0; 1.0] при 0.0 < fX < 1.0
        case RadiusDamage_Sin:
            fRes = floatsin(fX * 1.57, radian);
        case RadiusDamage_Tan:
            fRes = floattan(fX * 0.7854, radian);
        case RadiusDamage_Arcsin:
            fRes = (floatasin((fX - 0.5) * 2, radian) + 1.5) / 3;
    }

    return floatclamp(fRes, 0.0, 1.0);
}
 
Последнее редактирование:
Сообщения
936
Реакции
187
Помог
4 раз(а)
ArKaNeMaN, Получается голубой и оранжевый это линейный урон и будет меняться резко?
а по параболе урон плавно изменяется от минума к максимальному и также плавно уменьшается от центра?
 
Сообщения
392
Реакции
283
Помог
3 раз(а)
BiZaJe, не совсем понял вопрос)
Линейный там только сиреневый. Остальные, соответственно, нелинейные.
 
Сообщения
936
Реакции
187
Помог
4 раз(а)
ArKaNeMaN, Увидел, показалось, что 2 линии прямые, а они немного кривые
 
Сообщения
14
Реакции
-1
Код:
stock Float:rg_get_remaining_time()
{
    // Получаем значения из разделяемых переменных
    Float fRoundTimeSecs = get_member_game(m_iRoundTimeSecs);
    Float fRoundStartTimeReal = get_member_game(m_fRoundStartTimeReal);

    // Вычисляем текущее время
    Float fCurrentTime = get_gametime();

    // Вычисляем оставшееся время до конца раунда
    Float fRemainingTime = fRoundTimeSecs - fCurrentTime + fRoundStartTimeReal;

    // Возвращаем оставшееся время
    return fRemainingTime;
}
.
Получает время до конца раунда .
 
Сообщения
956
Реакции
51
Помог
10 раз(а)
mrnomore, #include <reapi> надо было бы дописать)
Код:
-Float fRoundTimeSecs
+new Float:fRoundTimeSecs
 
Последнее редактирование:
Сообщения
956
Реакции
51
Помог
10 раз(а)
А сам ты пробовал получить это время???
 
Сообщения
956
Реакции
51
Помог
10 раз(а)
mrnomore,
Код:
#include <amxmodx>
#include <reapi>

#define PLUGIN "test"
#define VERSION "1.0"
#define AUTHOR "test"

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

    register_clcmd("time", "@check_times");
}

@check_times(const id) {
    new sTime[MAX_NAME_LENGTH +1];
    rg_get_remaining_time(sTime, MAX_NAME_LENGTH);

    server_print("--------- sTime - [ %s ]", sTime);
}

stock rg_get_remaining_time(sTime[], const Len) {
    new Float:fRemainingTime = get_member_game(m_iRoundTimeSecs) - get_gametime() + get_member_game(m_fRoundStartTimeReal);
    server_print("--------- %.0f", get_member_game(m_iRoundTimeSecs));
    server_print("--------- %.0f", get_gametime());
    server_print("--------- %.0f", get_member_game(m_fRoundStartTimeReal));

    formatex(sTime, Len, "%.0f", fRemainingTime);
}
--------- 0
--------- 9
--------- 9
--------- sTime - [ 0 ]
 
Сообщения
14
Реакции
-1
Code_0xABC, formatex -> format с некоторыми версиями несовместимость, я бы рекомендовал format использовать.
Не объявил тип переменой sTime. В коде приведена функция rg_get_remaining_time, которая имеет параметр sTime[], но ты не не объявлен тип. Вероятность конечно маленькая что что могу возникнуть конфликты , но я бы объявил
 
Сообщения
580
Реакции
338
Предупреждения
1
Помог
9 раз(а)
mrnomore, это в каких версиях есть несовместимость formatex?
 
Сообщения
14
Реакции
-1
steelzzz, начиная с версии AMX Mod X 1.10.0 и выше, formatex был заменен на format, которая реализована внутри AMX Mod X и вызывает конфликт в редких случаях
 
Сообщения
936
Реакции
187
Помог
4 раз(а)
mrnomore, Это где ты такое вычитал? Прошел по всем обновам и ничего не было связано с заменой на format
и что значит 1.10 и выше? Когда 1.10 еще висит в разработке
 
Сообщения
14
Реакции
-1
mrnomore, Это где ты такое вычитал? Прошел по всем обновам и ничего не было связано с заменой на format
и что значит 1.10 и выше? Когда 1.10 еще висит в разработке
Ой точнее 1.9 , в гитхабе
 
  • Lol
Реакции: Arni
Сообщения
246
Реакции
268
Помог
2 раз(а)
mrnomore, хоть бы ссылку оставь, где написано) :lazy2:
 
Сообщения
956
Реакции
51
Помог
10 раз(а)
mrnomore, первый раз как все слышу такое про formatex, отличие format и farmatex тем, что в format можно обробатывать строку и сохранять в тот же массив, с formatex такое не прокатит, ну и с formatex пошустрее это все происходит, все!!!
Не объявил тип переменой sTime
, это ты о чем, для чего???? Я всего лишь в массив sTime записал значение твоей переменной fRemainingTime и все!!! И ответь на вопрос, что ты в итоге с помощью этого получишь????
Код:
new Float:fRemainingTime = get_member_game(m_iRoundTimeSecs) - get_gametime() + get_member_game(m_fRoundStartTimeReal);
Проверь, и ты опять же удивишся!!! :ok:
 
  • Нравится
Реакции: DEVV

Пользователи, просматривающие эту тему

Сейчас на форуме нет ни одного пользователя.
Сверху Снизу