Авторы:
Благодарность:
Требования:
Мультиязычность:
Refresh
Благодарность:
HLDS.RUN
Требования:
ReAPI, RefsAPI
Мультиязычность:
- RU
ACS True Flashbang — краткое описание
Назначение
Плагин заменяет штатную (движковую) модель ослепления от флешгранаты в CS 1.6 (
ReHLDS + ReAPI) на физически правдоподобную. Вместо двоичной логики «сзади / в лицо» считается реальная геометрия: угол между взглядом и источником, дистанция, перекрытие препятствием, накопление от повторных вспышек. Работает как для обычных игроков, так и для наблюдателей в режиме OBS_IN_EYE.
Какие дефекты движка (combat.cpp, RadiusFlash) устраняются
- Всего две градации по углу:
flDot < 0→ alpha 200;flDot >= 0→ alpha 255. Вспышка в 89° сбоку считается «в лицо» и слепит на полную. - Наследование силы:
if (m_blindAlpha >= alpha) alpha = m_blindAlpha;— слабая задняя вспышка усиливается до 255 после передней. - Отсев по телам: трасса
ВЗРЫВ → ИГРОКвыполняется сdont_ignore_monsters = 0(в ReHLDS этоMOVE_NORMAL), любое тело на линии считается твёрдым — игрок за чужими спинами не получаетScreenFadeвообще. - Случайный прицел: движок целится не в глаза, а в
BodyTarget = Center + view_ofs * RANDOM_FLOAT(0.5, 1.1)— игрок за низкой кромкой слепнет непредсказуемо (то да, то нет) при одинаковой геометрии.
Модель силы (acs_tfb_strength)
Единый сток расчёта, используется обоими путями (пересчёт
ScreenFade и дослепление):- Угол: косинус между forward-вектором взгляда и направлением на взрыв →
f_ang = (dot+1)/2, затемpow(f_ang, curve). - Близость (только при
dot >= 0, т.е. в передней полусфере): две зоны —dist <= fullblindдаётprox = 1.0(абсолютная слепота),fullblind < dist < closedistлинейно убывает, дальше 0.f_ang += (1-f_ang) * prox— близкий взрыв игнорирует угол. - Масштаб:
f_scale = minscale + (1-minscale) * f_ang— при 180° гарантированноminscale. - Перекрытие: трасса от глаз к взрыву, пропускает игроков, прозрачные энтити (
kRenderTransColor/Texture/Alpha/Add), маскированные текстуры ({-префикс,glass,window), и «касание пола» (отрезок корочеTFB_MIN_SEG). При перекрытииf_scale *= wallscale.
Накопление (две модели, acs_tfb_stack)
- 0 — композиция слоёв:
f_eff = 1 - (1-f_scale)(1-f_resid)(как наложение стёкол). - 1 — сложение света с насыщением (по умолчанию):
f_eff = min(1, f_scale + f_resid).
Остаточная засветка затухает линейно от силы последней вспышки до нуля.
Плато и спад хранятся раздельно (
gf_res_hold_end, gf_res_end) и складываются по разным законам:- Плато — по насыщению:
hold_end = max(old, now + hold*eff)(переэкспонировать белое нельзя). - Спад — по сбросу часов:
dur_end = max(old, hold_end + dur*eff)(прирост равен прошедшему времени, а не сумме длительностей).
Это устраняет прежний баг, когда
f_residual входил дважды с разными знаками и сокращался — остаток терялся целиком.
Дополнительные подсистемы
| Подсистема | Роль |
|---|---|
| acs_tfb_catchup | После взрыва в POST-хуке считает трассу от глаз (без кубика) и дослепляет тех, кого движок пропустил из-за случайного прицела. Своё сообщение помечается в gi_tfb_seen — повторно не пересчитывается. |
| acs_tfb_bodypass | POST-хук RG_RadiusFlash_TraceLine: если трасса упёрлась в живое тело, ставит flFraction = 1.0 — движок не отсекает по телам. Стены не трогает. |
| acs_tfb_teamfilter | Владелец берётся из gi_tfb_owner[]; своим ScreenFade давится в msg_screen_fade и не начисляется в catchup_apply. Самого владельца вспышка слепит (как в движке). |
| acs_tfb_view_target | Наблюдатель OBS_IN_EYE считает геометрию по наблюдаемому, но состояние накопления пишет только игрок (i_view == id), иначе один взрыв учёлся бы трижды. |
Цвет (_r/_g/_b) | Подставляется в аргументы 4/5/6 после фильтра белого (TFB_WHITE_MIN = 250), поэтому на распознавание флешки не влияет. |
Инженерные преимущества
- Единый расчёт:
acs_tfb_strengthвызывается и изcatchup_apply, и изmsg_screen_fade— исключено расхождение формул (в 1.2.4 дослепление подавало точку со смещением +1 по Z, а пересчёт — без). - Кэш перекрытия по ключу
(игрок, слот, поколение слота): трасса — самая дорогая операция, а один взрыв проверяется дважды. Поколение (gi_tfb_slot_gen) защищает от возврата чужого ответа при переиспользовании слота. - POST, не PRE в
RadiusFlash_TraceLine:TraceResultв оригинале объявлен без инициализации, а PRE-хуки идут до трассы —get_tr2(TR_pHit)на мусоре вызывалIndexOfEdict: bad entityи ронял сервер (реальный краш 30.10.2026). - POST, не таймер 0.02 с в дослеплении: работает в том же кадре, после того как движок разослал свои
ScreenFadeиmsg_screen_fadeвыставилseen[]. Сбросseen[]перенесён в PRE — иначе в POST метки движка уничтожались бы. - Кламп 16-битных полей (
TFB_SHORT_MAX) в обоих путях: раньше дослепление писалоf_dur*4096без ограничения, приcatchup_dur > 16 cзначение искажалось. - Самопроверка правки трассы: после
set_tr2перечитываетсяflFraction, в лог пишется «тело пропущено» или «ПРАВКА НЕ ПРИМЕНИЛАСЬ» — видно, работает ли хукчейн. - Безопасное чтение трассы: сначала
fraction, только потомpHit(приfraction = 1.0вpHitлежит NULL). - Быстрый путь
find_source: начинает с последнего слота, но всегда доходит до полного перебора и выбирает ближайший взрыв — в 1.2.5 раннийreturnприводил к выбору последнего взрыва при двух активных. - Нормировка только направления: forward из углов уже единичный, делим скалярное произведение на длину вектора к взрыву — минус три деления на вызов.
- Устойчивость к внешним сообщениям:
get_msg_args() < 7защищает от укороченныхScreenFadeсторонних плагинов,is_valid_player(id)— отid = 0приMSG_ALL. - Диагностика:
acs_tfb_debug = 1печатает фактические значения кваров при старте, разбор каждогоScreenFade(dot,prox,resid,eff,[BLOCKED],[OBS]), строкиnear:,trace:,catchup:— позволяет отличить «квар не работает» от «в конфиге старое значение».