Skip to content

Магический урон почти не проходит по мобам с резистами (бинарный MR-гейт 75% + стихийный резист) #3644

Description

@bylins

Продолжение #3643. Симптом: маг-дамаг (в т.ч. волхв, каст через obj) почти не проходит по мобам с резистами. Разобрал механику — вопрос балансный, на решение Свентовиту.

Правка: в первой версии я ошибочно написал про «некапнутый NPC-резист ≥200 → иммунитет». Резисты мобов клампятся (см. ниже), 200 недостижимо. Ниже — корректные числа.

Резисты мобов ограничены 95

src/gameplay/classes/recalc_mob_params_by_vnum.cpp:470 (и :488 для MR):

base_value = std::max(0, std::min(base_value, kMaxMobResist));  // kMaxMobResist = 95

И стихийные GET_RESIST, и GET_MR у мобов ограничены 95. Полного иммунитета через данные мобов нет.

Магический урон режется в двух местах

Ступень 1 — бинарный гейт по GET_MR (главный эффект)

CalcTotalSpellDmg, src/gameplay/magic/magic.cpp:338:

if (number(1,100) > std::min(ch->IsNpc() ? kMaxNpcResist : kMaxPcResist, GET_MR(victim))) {
    // считаем урон
}
// иначе total_dmg = 0 -- весь каст в ноль
  • ch — кастер. Игрок (ch->IsNpc()==false) → кап kMaxPcResist = 75.
  • Моб с MR >= 75number(1,100) > 75каст проходит лишь в 25% случаев, 75% гасятся полностью (всё-или-ничего).
  • Тот же принцип у дыхания: fight_hit.cpp:860. Механика давняя, не регрессия.

Константы: kMaxPcResist = 75 (resist.h), kMaxNpcResist = 100 (structs.h), kMaxMobResist = 95.

Ступень 2 — процентный стихийный резист ApplyResist

src/gameplay/mechanics/resist.cpp:84, применяется в damage.cpp:646 для kMagicDmg:

result = value - (resistance + number(0, resistance)) * value / 200.0;   // max(0, ...)

Срез = (R + rand(0,R))/200: в среднем 0.75*R %, максимум R %.

  • R = 75 → срез в среднем ~56%, максимум 75%.
  • R = 95 → срез в среднем ~71%, максимум 95%.

Это НЕ иммунитет — часть урона всегда проходит.

Итог

Моб MR≈75–95 + стихийный ≈95: бинарный гейт пропускает ~25% кастов, стихийный дорезает их ещё на ~71% в среднем → сквозь проходит ~7% номинала. Отсюда ощущение «магия не работает». Это суммарный эффект двух ступеней по дизайну, а не баг обнуления.

Про лог [MAG DAMAGE]

log("[MAG DAMAGE] …") (magic.cpp:619) стоит до расчёта урона, поэтому даже зарезиненный каст её пишет (кроме DoT-веток с ранним return). Резистами лог не гасится.

Развилка (нужно решение Свентовита)

  1. Смягчить бинарный MR-гейт для игроков — главный кандидат. Сейчас это all-or-nothing 75%. Сделать частичным (снижать урон, а не отсекать) либо понизить кап.
  2. Пересмотреть стек двух резистов (MR-гейт + стихийный) — не слишком ли жёстко вместе.
  3. Код не трогать — считать, что конкретные мобы перекручены по MR/резистам в данных, править мир.

Числа и путь — за Свентовитом. По готовности решения сделаю точечный фикс.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions