Следуйте инструкциям в видео ниже, чтобы узнать, как установить наш сайт как веб-приложение на главный экран вашего устройства.
Примечание: Эта функция может быть недоступна в некоторых браузерах.
stock is_wall_between_points(Float: start[3], Float: end[3], ignore_ent) {
// Create the trace handle! It is best to create it!
new ptr = create_tr2()
// The main traceline function!
// This function ignores GLASS, MISSILE and MONSTERS!
// Here is an example of how you should combine all the flags!
engfunc(EngFunc_TraceLine, start, end, IGNORE_GLASS | IGNORE_MONSTERS | IGNORE_MISSILE, ignore_ent, ptr)
// We are interested in the fraction parameter
new fraction
get_tr2(ptr, TR_flFraction, fraction)
// Free the trace handle (don't forget to do this!)
free_tr2(ptr)
// If = 1.0 then it didn't hit anything!
return (fraction != 1.0)
}
/**
* Парсинг строки для получения времени в секундах
*
* @param szTime Строка для парсинга
*
* @return Время в секундах
*/
stock parseTime(const szTime[])
{
const SecondsInMinute = 60;
const SecondsInHour = 3600;
const SecondsInDay = 86400;
const SecondsInWeek = 604800;
const SecondsInMonth = 25920000;
const SecondsInYear = 31536000;
new k, t, h, bool:check_chars;
for (new i; szTime[i] != EOS; i++)
{
if (isspace(szTime[i]))
{
check_chars = true;
continue;
}
switch(szTime[i])
{
case '0'..'9':
{
if (check_chars)
{
check_chars = false;
k += t;
}
t = (t * 10) + (szTime[i] - '0');
}
case 's', 'S':
{
k += t;
t = 0;
}
case 'i','I':
{
k += t * SecondsInMinute;
t = 0;
}
case 'h','H':
{
k += t * SecondsInHour;
t = 0;
}
case 'd','D':
{
k += t * SecondsInDay;
t = 0;
}
case 'w','W':
{
k += t * SecondsInWeek;
t = 0;
}
case 'm','M':
{
k += t * SecondsInMonth;
t = 0;
}
case 'y','Y':
{
k += t * SecondsInYear;
t = 0;
}
default:
{
break;
}
}
}
return k + t;
}
/**
* Замена для SQL запроса
*
* @param szDest Строка
* @param iLen Длина строки
*
* @noreturn
*/
stock UTIL_SqlEscapeString(szDest, const iLen)
{
replace_all(szDest, iLen, "\\", "\\\\");
replace_all(szDest, iLen, "\0", "\\0");
replace_all(szDest, iLen, "\n", "\\n");
replace_all(szDest, iLen, "\r", "\\r");
replace_all(szDest, iLen, "\x1a", "\Z");
replace_all(szDest, iLen, "'", "\'");
replace_all(szDest, iLen, "^"", "\^"");
}
/**
* Получает размеры хитбоксов у модели (динамически)
*
* @param szModel Путь до модели (Пр. "models/bag.mdl")
* @param flMaxs Local BB max.
* @param flMins Local BB min.
* @param flSize max - min
*
* @return true/false
*/
stock bool:UTIL_GetModelHitBox(const szModel[], Float: flMaxs[3], Float: flMins[3], Float: flSize[3])
{
new hFile = fopen(szModel, "rb");
if (!hFile)
{
server_print("Can`t open %s", szModel);
return false;
}
fseek(hFile, 160, SEEK_SET);
new iBlock;
fread(hFile, iBlock, BLOCK_INT);
fseek(hFile, iBlock + 8, SEEK_SET);
new Float: flVec[6];
fread_blocks(hFile, _:flVec, 6, BLOCK_INT);
fclose(hFile);
flMins[0] = flVec[0];
flMins[1] = flVec[1];
flMins[2] = flVec[2];
flMaxs[0] = flVec[3];
flMaxs[1] = flVec[4];
flMaxs[2] = flVec[5];
flSize[0] = flVec[3] - flVec[0];
flSize[1] = flVec[4] - flVec[1];
flSize[2] = flVec[5] - flVec[2];
return true;
}
Неправильный сток, поскольку намешаны CTRLCHAR "\" и "^", должно быть, для "^" (по-умолчанию):stock UTIL_SqlEscapeString(szDest, const iLen)
#define _SC(%0) %0, charsmax(%0)
replace_all(_SC(s_tmp), "^r", "");
replace_all(_SC(s_tmp), "^n", "");
replace_all(_SC(s_tmp), "^t", "");
replace_all(_SC(s_tmp), "^x1a", "");
replace_all(_SC(s_tmp), "\", "\\");
replace_all(_SC(s_tmp), "`", "\`");
replace_all(_SC(s_tmp), "^'", "\^'");
replace_all(_SC(s_tmp), "^"", "\^"");
stock UTIL_SqlEscapeString(const str[]) {
new i, j, result[ACS_MAX_BUFFER_SIZE];
for (; str[i] && j < charsmax(result); i++) {
switch (str[i]) {
case '^r', '^n', '^t', '^x1a':
continue;
case '`', '^'', '^"', '\': {
result[j++] = '\';
if (j >= charsmax(result))
break;
}
}
result[j++] = str[i];
}
return result;
}
Потрясающие названия переменных. Когда уже забудете про венгерскую нотацию?i_i, i_j
Потрясающие названия переменных. Когда уже забудете про венгерскую нотацию?
Возвращать из функции массив не очень хорошая идея. Во первых, будет лишнее копирование массива из стэка. Во вторых, размер массива ограничивается в функции. В третьих, всегда создается новый массив, даже когда он не нужен.
#define инклуда ваших проектов, обычно буфер 256 ячеек.formatex(_SC(s_query), "SELECT * FROM `player_names` WHERE name = '%s'", _qq(s_name));
Я не просто так придираюсь. Этот топик для примеров кода, верно? Логично ведь тогда подавать хорошие примеры.Это пример, можно перевести на любую нотацию.
Вообще-то, можно избежать копирования, но при этом, алгоритм будет сложнее, что в данном случае не желательно и не имеет смысла.Копирование будет в любом случае
Используетсямассив s_result тогда уж должен быть статическим, потому что при больших размерах массива
new чтобы избежать необходимости писать 0 в конец строки, никаких проблем со стеком не возникало даже на стандарном #pragma dynamic.%n я вырезал из всех плагинов из-за особенности реализации форматирования для отключившегося игрока - он выдает имя сервера. Я форматирую тысячи запросов во вспомогательных плагинах и выполняю их с определенной приоритезацией в десятки потоков в основном - на полном сервере это в сотни раз быстрее, даже если использовать дохлый db4.myarena.ru. Я считаю, что накладные расходы на использование штатных нативов sqlx для этой задачи, кратно больше, "корявей" и не имеет смысла. Я привык получать все данные "одной строкой":g_acs_client[id][acs_cl_ip_db_id] = rf_sql_nm_field(query, "id");
rf_sql_nm_field_str_c(query, "country", acs_cl_country);
#include <amxmodx>
#define test_function(%0) (charsmax(%0))
#define CONST_VAR1 "test"
#define CONST_VAR2 1
#define CONST_VAR3 1.0
#define CONST_VAR4 true
new const CONST_VAR5[] = "test";
const CONST_VAR6 = 1;
const bool:CONST_VAR7 = true;
const Float:CONST_VAR8 = 1.0;
enum Struct {
DATA1,
DATA2,
DATA3
};
new GlobalVar1[Struct];
new GlobalVar2 = 1;
new bool:GlobalVar3 = true;
new Float:GlobalVar4 = 1.0;
public plugin_init() {
register_plugin("Test CodeStyle", "1.0.0", "Albertio");
new localVar1[Struct];
new localVar2 = 1;
new bool:localVar3 = true;
new Float:localVar4 = 1.0;
}
Данный сток предназначен для для проверки наличия физических препятствий (в основном стен) между двумя точками. Метод выполняет трассировку луча между заданными координатами, игнорируя стекло, монстров, игроков и снаряды, и возвращает true, если луч столкнулся с чем-то на пути, и false, если путь свободен.
Код:stock is_wall_between_points(Float: start[3], Float: end[3], ignore_ent) { // Create the trace handle! It is best to create it! new ptr = create_tr2() // The main traceline function! // This function ignores GLASS, MISSILE and MONSTERS! // Here is an example of how you should combine all the flags! engfunc(EngFunc_TraceLine, start, end, IGNORE_GLASS | IGNORE_MONSTERS | IGNORE_MISSILE, ignore_ent, ptr) // We are interested in the fraction parameter new fraction get_tr2(ptr, TR_flFraction, fraction) // Free the trace handle (don't forget to do this!) free_tr2(ptr) // If = 1.0 then it didn't hit anything! return (fraction != 1.0) }
public fw_TraceAttack_Pre(victim, attacker, Float:damage, Float:direction[3], tracehandle, damageBits)
{
if (!get_pcvar_num(g_iCvar))
return HC_CONTINUE;
if (!(damageBits & DMG_BULLET))
return HC_CONTINUE;
if (!is_user_connected(attacker) || !is_user_alive(attacker))
return HC_CONTINUE;
if (!is_user_connected(victim) || !is_user_alive(victim))
return HC_CONTINUE;
new weapon = get_member(attacker, m_pActiveItem);
if (!weapon)
return HC_CONTINUE;
new WeaponIdType:weaponId = get_member(weapon, m_iId);
if (weaponId == WEAPON_M3 || weaponId == WEAPON_XM1014)
return HC_CONTINUE;
new Float:vecSrc[3], Float:vecEnd[3], Float:vecViewOfs[3];
get_entvar(attacker, var_origin, vecSrc);
get_entvar(attacker, var_view_ofs, vecViewOfs);
xs_vec_add(vecSrc, vecViewOfs, vecSrc);
get_tr2(tracehandle, TR_vecEndPos, vecEnd);
new trace = create_tr2();
engfunc(EngFunc_TraceLine, vecSrc, vecEnd, IGNORE_MONSTERS | IGNORE_GLASS, attacker, trace);
new Float:fraction;
get_tr2(trace, TR_flFraction, fraction);
new hitEnt = get_tr2(trace, TR_pHit);
free_tr2(trace);
if (fraction < 1.0 && hitEnt != victim)
{
SetHookChainReturn(ATYPE_INTEGER, 0);
return HC_SUPERCEDE;
}
return HC_CONTINUE;
}
Смотря для чего. Первый код всего лишь проверяет на наличие препятствия от трейса точки А до точки В. Второй код блочит нормальное поведение функции в случае, если на пути трейса от точки А до точки В было препятствие и попадание было зарегистрировано не в жертву. А в жертву так и так зарегано попадание не будет, потому что второй трейс идет с флагом IGNORE_MONSTERS, поэтому надобность во втором блоке условияэтот код мб лучше?
if (fraction < 1.0 && hitEnt != victim)
Все верноСмотря для чего. Первый код всего лишь проверяет на наличие препятствия от трейса точки А до точки В. Второй код блочит нормальное поведение функции в случае, если на пути трейса от точки А до точки В было препятствие и попадание было зарегистрировано не в жертву. А в жертву так и так зарегано попадание не будет, потому что второй трейс идет с флагом IGNORE_MONSTERS, поэтому надобность во втором блоке условияавтоматически отпадаетКод:if (fraction < 1.0 && hitEnt != victim)
// blinksNum - Количество миганий.
// playerId - Айди игрока или 0 для всех.
// duration - Продолжительность эффекта затухания в секундах.
// holdTime - Время в секундах, необходимое для удержания затухания на максимальном уровне перед его исчезновением.
// color1 - Первый цвет(указывать в виде RGBA).
// color2 - Второй цвет(указывать в виде RGBA).
// isBlind - Проверять игрока на слепоту(если под флешкой, то мессага ему не отправляется).
PlayerScreenBlinking(10, playerId, 0.15, 0.15, {255, 0, 0, 100}, {0, 255, 0, 100}, true);
enum _:RGBA {
R,
G,
B,
A
};
enum _:MessageDataStruct {
RECIPIENT_ID,
Float:DURATION,
Float:HOLD_TIME,
COLOR1[RGBA],
COLOR2[RGBA],
bool:IS_BLIND
};
enum _:TaskDataStruct {
ARRAY_HANDLE,
BLINKS_NUM,
BLINKS_ITER
};
stock PlayerScreenBlinking(
const blinksNum = 10,
const playerId,
const Float:duration = 1.0,
const Float:holdTime = 1.0,
const color1[RGBA] = {255, 255, 255, 255},
const color2[RGBA] = {255, 255, 255, 255},
const bool:isBlind = true
) {
const TASK_ID_BASE = 13131313;
new messageData[MessageDataStruct];
messageData[RECIPIENT_ID] = playerId;
messageData[DURATION] = duration;
messageData[HOLD_TIME] = holdTime;
messageData[COLOR1][R] = color1[R];
messageData[COLOR1][G] = color1[G];
messageData[COLOR1][B] = color1[B];
messageData[COLOR1][A] = color1[A];
messageData[COLOR2][R] = color2[R];
messageData[COLOR2][G] = color2[G];
messageData[COLOR2][B] = color2[B];
messageData[COLOR2][A] = color2[A];
messageData[IS_BLIND] = isBlind;
new Array:messageDataArray = ArrayCreate(MessageDataStruct);
ArrayPushArray(messageDataArray, messageData);
new taskData[TaskDataStruct];
taskData[ARRAY_HANDLE] = any:messageDataArray;
taskData[BLINKS_NUM] = blinksNum;
for(new i = 1; i <= blinksNum; i++) {
taskData[BLINKS_ITER] = i;
set_task(duration * i, "ScreenBlinkingTask", TASK_ID_BASE, taskData, sizeof(taskData));
}
}
public ScreenBlinkingTask(taskData[TaskDataStruct]) {
new messageData[MessageDataStruct];
new Array:messageDataArray = any:taskData[ARRAY_HANDLE];
ArrayGetArray(messageDataArray, 0, messageData);
if(taskData[BLINKS_NUM] == taskData[BLINKS_ITER])
ArrayDestroy(messageDataArray);
new color[RGBA];
if(taskData[BLINKS_ITER] % 2) {
color[R] = messageData[COLOR1][R];
color[G] = messageData[COLOR1][G];
color[B] = messageData[COLOR1][B];
color[A] = messageData[COLOR1][A];
} else {
color[R] = messageData[COLOR2][R];
color[G] = messageData[COLOR2][G];
color[B] = messageData[COLOR2][B];
color[A] = messageData[COLOR2][A];
}
SendScreenFadeMessage(
messageData[RECIPIENT_ID],
messageData[DURATION],
messageData[HOLD_TIME],
color,
messageData[IS_BLIND]
);
}
stock SendScreenFadeMessage(
const playerId,
const Float:duration = 1.0,
const Float:holdTime = 1.0,
const color[RGBA] = {255, 255, 255, 255},
const bool:isBlind = true
) {
const FFADE_OUT = 0x0001;
static msgId;
if(msgId == 0 && (msgId = get_user_msgid("ScreenFade")) == 0)
return;
for(new i = (playerId == 0) ? 1 : playerId; i <= MaxClients; i++) {
if(!is_user_connected(i))
continue;
if(isBlind && PlayerIsBlind(i))
continue;
message_begin(MSG_ONE_UNRELIABLE, msgId, {0, 0, 0}, i);
write_short(FixedUnsigned16(duration));
write_short(FixedUnsigned16(holdTime));
write_short(FFADE_OUT);
write_byte(color[R]);
write_byte(color[G]);
write_byte(color[B]);
write_byte(color[A]);
message_end();
}
}
stock bool:PlayerIsBlind(const playerId) {
return bool:(Float:get_member(playerId, m_blindUntilTime) > get_gametime());
}
stock FixedUnsigned16(Float:value) {
return clamp(floatround(value * 4096.0), 0, 0xFFFF);
}