/**
История изменений:
0.1 (15.10.2021) by b0t.
- Первый релиз;
0.2 (28.05.2022) by b0t.
- rg_set_user_health() -> rg_add_user_health();
- UTIL__CreateExplode() -> UTIL__CreateExplodeGrenade();
- rg_add_user_armor();
- rg_users_1vs1();
- rg_get_team_score_diff();
- rg_get_team_count_diff();
- rg_is_user_first_spawn();
- UTIL__RemoveEntity();
- UTIL__GetFlashState();
- UTIL__RecordMessageInArray();
*/
#define INCLUDE_VERSION "0.2"
#if !defined _reapi_included
#include <reapi>
#endif
#if !defined _xs_included
#include <xs>
#endif
#if !defined _fakemeta_included
#include <fakemeta>
#endif
#if defined _reapi_v_included
#endinput
#endif
#define _reapi_v_included
enum PERCENT_DATA {
_IS_, //Какое число соответствует N процентов от исходного;
_GET_, //Сколько процентов составляет N-е число от исходного;
_ADD_, //Добавить N процентов к числу;
_SUB_ //Вычесть N процентов от числа;
};
enum FLASH_STATE {
FLASH_NONE = 0, //Ослепления нет;
FLASH_TIME, //Уже имеются просветы;
FLASH_HOLD //Ни чего не видно;
};
enum _:XYZ {
Float:X,Float:Y,Float:Z
};
enum _:RGB {
Float:R,Float:G,Float:B
};
#define IsValidPlayer(%0) (1<=%0<=MaxClients)
/**
* Узнать есть ли у игрока 'бессмертие'.
*
* @param pPlayer Игрок.
*
* @return bool
*/
stock bool:rg_get_user_godmode(const pPlayer) {
return bool:(Float:get_entvar(pPlayer,var_takedamage) == DAMAGE_NO);
}
/**
* Выдать/Забрать игроку 'бессмертие'.
*
* @param pPlayer Игрок.
* @param bType Включить/отключить
*
* @return -
*/
stock rg_set_user_godmode(const pPlayer,const bool:bType = false) {
set_entvar(pPlayer,var_takedamage,bType ? DAMAGE_NO : DAMAGE_YES);
}
/**
* Узнать есть ли у игрока 'ноклип'.
*
* @param pPlayer Игрок.
*
* @return bool
*/
stock bool:rg_get_user_noclip(const pPlayer) {
return bool:(get_entvar(pPlayer,var_movetype) == MOVETYPE_NOCLIP);
}
/**
* Выдать/Забрать игроку 'ноклип'.
*
* @param pPlayer Игрок.
* @param bType Включить/отключить
*
* @return -
*/
stock rg_set_user_noclip(const pPlayer,const bool:bType = false) {
set_entvar(pPlayer,var_movetype,bType ? MOVETYPE_NOCLIP : MOVETYPE_WALK);
}
/**
* Сделает объект видимым/невидимым.
*
* @param iEnt Объект
* @param bHide Выключить/включить
*
* @return -
*/
stock rg_set_entity_invisibility(const iEnt, bool:bHide = true) {
new iFlags = get_entvar(iEnt,var_effects);
set_entvar(iEnt,var_effects,bHide ? (iFlags |= EF_NODRAW) : (iFlags &= ~EF_NODRAW))
}
/**
* Узнать видно ли объект.
*
* @param iEnt Объект
*
* @return true -- если не видно
*/
stock bool:rg_get_user_invisibility(const iEnt) {
return bool:(get_entvar(iEnt, var_effects) & EF_NODRAW)
}
/**
* Какую скорость имеет игрок.
*
* @param pPlayer Игрок.
*
* @return float
*/
stock Float:rg_get_user_maxspeed(const pPlayer) {
return Float:get_entvar(pPlayer,var_maxspeed);
}
/**
* Устанавливает игроку скорость.
*
* @param pPlayer Игрок.
* @param fSpeed Скорость(float)
*
* @return -
*/
stock rg_set_user_maxspeed(const pPlayer, Float:fSpeed = -1.0) {
if(speed != -1)
set_entvar(pPlayer,var_maxspeed,speed);
else
rg_reset_maxspeed(pPlayer);
}
/**
* Устанавливает игроку гравитацию.
*
* @param pPlayer Игрок.
* @param fGravity Гравитация(float)
*
* @return -
*/
stock rg_set_user_gravity(const pPlayer,Float:fGravity = 1.0) {
set_entvar(pPlayer,var_gravity,gravity);
}
/**
* Какую гравитацию имеет игрок.
*
* @param pPlayer Игрок.
*
* @return float
*/
stock Float:rg_get_user_gravity(const pPlayer) {
return Float:get_entvar(pPlayer,var_gravity);
}
/**
* Вернёт true если у игрока есть прибор ночного виденья.
*
* @param pPlayer Игрок.
*
* @return bool
*/
stock bool:rg_get_user_nvg(const pPlayer) {
return bool:(get_member(pPlayer,m_bHasNightVision));
}
/**
* Выдаёт игроку прибор ночного виденья.
*
* @param pPlayer Игрок.
* @param bNvg false/true
*
* @return -
*/
stock rg_set_user_nvg(const pPlayer,bool:bNvg = true) {
set_member(pPlayer,m_bHasNightVision,bNvg);
}
/**
* Устанавливает эффекты объекту
* @NOTE: Необходимые константы можно найти в 'amxconst.inc'
*
* @param iEnt Объект
* @param iFx Эффекты
* @param fColor Цвет = Float:{R,G,B}
* @param iRender Режим рендеринга. Одна из констант kRender*
* @param iAmount Объём (0-255)
*
* @return -
*/
stock rg_set_entity_rendering(const iEnt,
const iFx = kRenderFxNone,
const Float:fColor[] = {255.0,255.0,255.0},
const iRender = kRenderNormal,
const iAmount = 16) {
set_entvar(iEnt,var_renderfx,iFx);
set_entvar(iEnt,var_rendercolor,fColor);
set_entvar(iEnt,var_rendermode,iRender);
set_entvar(iEnt,var_renderamt,float(iAmount));
}
/**
* Прибавит игроку здоровье
*
* @param pPlayer Игрок
* @param fHp Здоровье
* @param bIsMax Использовать мнимальный/максимальные значения(false/true)
* @param fHpMin Минимальное кол-во здоровья
* @param fHpMax Максимальное кол-во здоровья
*
* @return -
*/
stock rg_add_user_health(const pPlayer,const Float:fHp,const bool:bIsMax = false,const Float:fHpMin = 1.0,const Float:fHpMax = 100.0) {
if(bIsMax)
set_entvar(pPlayer,var_health,floatclamp((Float:get_entvar(pPlayer,var_health)+fHp),fHpMin,fHpMax));
else
set_entvar(pPlayer,var_health,Float:get_entvar(pPlayer,var_health)+fHp);
}
/**
* Прибавит игроку Броню
*
* @param pPlayer Игрок
* @param fAr Броня
* @param bIsMax Использовать мнимальный/максимальные значения(false/true)
* @param fArMin Минимальное кол-во брони
* @param fArMax Максимальное кол-во брони
*
* @return -
*/
stock rg_add_user_armor(const pPlayer,const Float:fAr,const bool:bIsMax = false,const Float:fArMin = 1.0,const Float:fArMax = 100.0) {
if(bIsMax)
set_entvar(pPlayer,var_armorvalue,floatclamp((Float:get_entvar(pPlayer,var_armorvalue)+fAr),fArMin,fArMax));
else
set_entvar(pPlayer,var_armorvalue,Float:get_entvar(pPlayer,var_armorvalue)+fAr);
}
/**
* Заморозит/разморозит объект
*
* @param iEnt Объект
* @param bFreez tru -- заморозит
*
* @return -
*/
stock rg_set_entity_frozen(const iEnt,const bool:bFreez = false) {
new iFlags = get_entvar(iEnt,var_flags);
set_entvar(iEnt,var_flags,bFreez ? (iFlags |= FL_FROZEN) : (iFlags &~ FL_FROZEN));
}
/**
* Проверит если остались 1 на 1
* @NOTE: by Emma Jule
*
*
* @return bool
*/
stock bool:rg_users_1vs1() {
new iAliveTs,iAliveCTs;
rg_initialize_player_counts(iAliveTs,iAliveCTs);
return bool:(iAliveTs == 1 && iAliveCTs == 1);
}
/**
* Получим разницу между победами КТ и ТТ
* @NOTE: by Emma Jule
*
*
* @return int
*/
stock rg_get_team_score_diff() {
return abs(get_member_game(m_iNumTerroristWins) - get_member_game(m_iNumCTWins));
}
/**
* Получим разницу между кол-вом игроков КТ и ТТ
* @NOTE: by Emma Jule
*
*
* @return int
*/
stock rg_get_team_count_diff() {
return abs(get_member_game(m_iNumTerrorist) - get_member_game(m_iNumCT));
}
/**
* Проверим является ли это первым спавном игрока
* @NOTE: by Emma Jule
*
*
* @return bool
*/
stock bool:rg_is_user_first_spawn(const pPlayer) {
return bool:(get_member(pPlayer,m_iNumSpawns) == 1);
}
/**
* "Передаст" деньги одного игрока другому
*
* @param pPlayer Игрок со счёта которого будем списывать
* @param pSender Игрок, на счёт которому будем зачислять
* @param iAmmount Сумма
* @param bUpdateHud Обновлять худ денег
*
* @return -
*/
stock UTIL__TransferMoney(const pPlayer,const pSender,const iAmmount,const bool:bUpdateHud = false) {
rg_add_account(pPlayer,-iAmmount,AS_SET,bUpdateHud);
rg_add_account(pSender,iAmmount,AS_SET,bUpdateHud);
}
/**
* Удалит ключи цветов из строки
*
* @param szMessage Массив с сообщением
* @param iMaxLen Максимальный размер массива
* @param bMenu true -- Удалять цвета из меню | false -- из чата
*
* @return -
*/
stock UTIL__ReplaceSimbols(szMessage[],const iMaxLen,const bool:bMenu = true) {
switch(bMenu) {
case true: {
replace_all(szMessage,iMaxLen,"\r","");
replace_all(szMessage,iMaxLen,"\y","");
replace_all(szMessage,iMaxLen,"\d","");
replace_all(szMessage,iMaxLen,"\w","");
}
case false: {
replace_all(szMessage,iMaxLen,"^4","");
replace_all(szMessage,iMaxLen,"^2","");
replace_all(szMessage,iMaxLen,"^1","");
}
}
}
/**
* Зарегистрирует команду во всех чатах + консоль
*
* @param szCmd Команда
* @param szFunc Функция обработчик
*
* @return -
*/
stock UTIL__RegisterClCmd(const szCmd[],const szFunc[]) {
register_clcmd(fmt("%s",szCmd),szFunc);
register_clcmd(fmt("say /%s",szCmd),szFunc);
register_clcmd(fmt("say_team /%s",szCmd),szFunc);
}
/**
* Отображает меню игроку
* @NOTE: Если игрока нет на сервере -- уничтожит меню для избежания утечек памяти
*
* @param pPlayer Игрок
* @param iMenu Меню
* @param szNextName Оформление кнопки "Далее"
* @param szBackName Оформление кнопки "Назад"
* @param szExitName Оформление кнопки "Выход"
* @param szNumberColor Цвет номеров (1,2,3...)
* @param iPage С какой страницы открыть меню
*
* @return -
*/
stock UTIL__RegisterMenu(const pPlayer,
const iMenu,
const szNextName[] = "Назад",
const szBackName[] = "Далее",
const szExitName[] = "Выход",
const szNumberColor[] = "\y",
const iPage = 0) {
if(menu_items(iMenu) <= 0 || !is_user_connected(pPlayer))
menu_destroy(iMenu);
else {
menu_setprop(iMenu,MPROP_NEXTNAME,szNextName);
menu_setprop(iMenu,MPROP_BACKNAME,szBackName);
menu_setprop(iMenu,MPROP_EXITNAME,szExitName);
menu_setprop(iMenu,MPROP_NUMBER_COLOR,szNumberColor);
menu_display(pPlayer,iMenu,iPage);
}
}
/**
* Воспроизведёт звук игроку/всем
*
* @param pPlayer Игрок (0 если всем)
* @param szSound Звук в формате (.wav/.mp3)
* @param bStopSound Остановить предыдущие(костыль)
*
* @return -
*/
stock UTIL__PlaySound(const pPlayer = 0,const szSound[],const bool:bStopSound = false) {
if (bStopSound)
client_cmd(pPlayer, "mp3 stop;stopsound");
if(containi(szSound,".mp3") != -1)
client_cmd(pPlayer,"mp3 play ^"sound/%s^"", szSound);
else
client_cmd(pPlayer,"spk ^"%s^"", szSound);
}
/**
* Выдаёт игроку оружие
* @NOTE: аналог rg_give_item(); с возможностью сразу задать патроны в запас/обойму
*
* @param pPlayer Игрок
* @param szWeaponName Имя оружия (без weapon_)
* @param iGiveType Как выдать
* @param iAmmo Патроны в обойму
* @param iBpAmmo Патроны в запас
*
* @return -
*/
stock UTIL__GiveWeapon(const pPlayer,const szWeaponName[],const GiveType:iGiveType = GT_DROP_AND_REPLACE,const iAmmo = 0,const iBpAmmo = 0) {
new iWeapon = rg_give_item(pPlayer,fmt("weapon_%s",szWeaponName),iGiveType);
if(is_nullent(iWeapon))
return;
new WeaponIdType:iWeaponID = get_member(iWeapon,m_iId);
if(iAmmo)
rg_set_user_ammo(pPlayer,iWeaponID,iAmmo);
if(iBpAmmo)
rg_set_user_bpammo(pPlayer,iWeaponID,iBpAmmo);
}
/**
* Создаст имитацию взрыва гранаты
*
* @param pOwner Владелец взрыва
* @param fOrigin Координаты(эпицентр)
* @param fDamage Урон(чем дальше от эпицентра тем меньше урон)
* @param fRadius Радиус взрыва
*
* @return -
*/
stock UTIL__CreateExplodeGrenade(const pOwner = 0,Float:fOrigin[XYZ] = {0.0,0.0,0.0},const Float:fDamage = 0.0,const Float:fRadius = 0.0) {
new iEnt = rg_create_entity("grenade", .useHashTable = true);
if(is_nullent(iEnt))
return
if(pOwner)
set_member(iEnt,m_Grenade_iTeam,get_member(pOwner,m_iTeam));
set_entvar(iEnt,var_owner,pOwner);
rg_dmg_radius(fOrigin,iEnt,pOwner,fDamage,fRadius,0,DMG_GRENADE);
set_entvar(iEnt,var_flags,FL_KILLME);
}
/**
* Найдёт координаты неба
*
* @param fOrigin Начальные координаты для поиска
*
* @return float
*/
stock UTIL__GetSkyOrigin(Float:fOrigin[XYZ]) {
new iEntSky = engfunc(EngFunc_PointContents,fOrigin);
while(iEntSky != CONTENTS_SKY) {
fOrigin[Z] += 1.0;
iEntSky = engfunc(EngFunc_PointContents,fOrigin);
}
}
/**
* Установить скорость объекту
*
* @param iEnt Объект
* @param fSpeed Скорость
* @param fOriginStart Начальные координаты
* @param fOriginEnd Конечные координаты
* @param bSetAngles Установить углы по пути движения
*
* @return -
*/
stock UTIL__SetEntitySpeed(const iEnt,const Float:fSpeed,const Float:fOriginStart[XYZ],const Float:fOriginEnd[XYZ],const bool:bSetAngles = false) {
new fDistance = get_distance_f(fOriginStart,fOriginEnd);
new fSetSpeed = fSpeed/fDistance;
new Float:fVelocity[XYZ];
get_entvar(iEnt,var_velocity,fVelocity);
xs_vec_sub(fOriginEnd,fOriginStart,fVelocity);
xs_vec_mul_scalar(fVelocity,fSpeed,fVelocity);
set_entvar(iEnt,var_velocity,fVelocity);
if(bSetAngles) {
vector_to_angle(fVelocity,fAngles);
set_entvar(iEnt,var_angles,fAngles);
}
}
/**
* Работа с процентами
*
* @param iType Как производить расчёт (См. PERCENT_DATA)
* @param fNum Число
* @param fPercent Проценты
*
* @return float
*/
stock UTIL__GetPercent(const PERCENT_DATA:iType = _IS_,const Float:fNum = 0.0,const Float:fPercent = 0.0) {
new Float:fRatio
switch(iType) {
case _IS_: return ((fNum/100.0) * fPercent);
case _GET_: return ((fNum/fPercent) / 100.0)
case _ADD_: {
fRatio = fNum/100.0;
return ((fRatio*fPercent) + fNum);
}
case _SUB_: {
fRatio = fNum/100.0;
return ((fRatio*fPercent) - fNum);
}
}
}
/**
* Удалит все объекты с указанным классом
*
* @param szClassName Класс объекта
*
* @return -
*/
stock UTIL__RemoveEntity(const szClassName[] = "") {
new iEntity = -1;
while((iEntity = rg_find_ent_by_class(iEntity,szClassName))) {
set_entvar(iEntity,var_flags,FL_KILLME);
}
}
/**
* Узнать степень ослепления игрока
* @NOTE: Спасибо за помощь 'Denzer'
* Source: https://dev-cs.ru/threads/17049/post-111311
*
* @param pPlayer Игрок
*
* @return int
*/
stock FLASH_STATE:UTIL__GetFlashState(const pPlayer) {
new Float:flStartTime = Float:get_member(pPlayer, m_blindStartTime);
new Float:flGameTime = get_gametime();
if(flStartTime + Float:get_member(pPlayer, m_blindHoldTime) >= flGameTime)
return FLASH_HOLD;
if(flStartTime + Float:get_member(pPlayer, m_blindFadeTime) >= flGameTime)
return FLASH_TIME;
return FLASH_NONE;
}
/**
* Разделит строку и запишет её в массив, типа 'Array', в виде отдельных аргументов или чисел
* @NOTE: Используется для записи в ячейки массива тапа 'Array' отдельных данных разделённых Спец. символом.
* Пример: szMessage[] = "Test1|Test2|Test3"
* UTIL__RecordMessageInArray(ArrayTest,szMessage,'|');
*
* На выходе получим:
* new szArrayItem_One[64];
* ArrayGetString(ArrayTest,1,szArrayItem_One,charsmax(szArrayItem_One));
* szArrayItem_One = Test2
*
* @param ArrayData Array
* @param szMessage Строка
* @param szSimbol Разделяющий символ
* @param bCell false -- если строка
*
* @return -
*/
stock UTIL__RecordMessageInArray(Array:ArrayData,const szMessage[],const szSimbol = ' ',bool:bCell = false) {
new szLeft[256],szRight[256];
strtok(szMessage,szLeft,charsmax(szLeft),szRight,charsmax(szRight),szSimbol);
if(bCell)
ArrayPushCell(ArrayData,str_to_num(szLeft));
else
ArrayPushString(ArrayData,szLeft);
while(szRight[0] != EOS && strtok(szRight,szLeft,charsmax(szLeft),szRight,charsmax(szRight),szSimbol)) {
if(bCell)
ArrayPushCell(ArrayData,str_to_num(szLeft));
else
ArrayPushString(ArrayData,szLeft);
}
}