Skip to content

fix(poison): stop the per-fight latch from re-granting a guaranteed poison - #4097

Merged
bylins merged 1 commit into
masterfrom
fix/poison-guaranteed-proc-per-fight
Oct 24, 2026
Merged

bylins merged 1 commit into
masterfrom
fix/poison-guaranteed-proc-per-fight

Conversation

@bylins

@bylins bylins commented Oct 23, 2026

Copy link
Copy Markdown
Owner

Жалоба

Игрок заметил: бьешь моба оружием с беленой — первое наложение проходит гарантированно, как и задумано. Но если отбежать и вернуться, следующий удар снова кладет яд со стопроцентной вероятностью, хотя прежний еще держится. «Стоя в бою накладываются с мелким шансом, а если бегать — друг за другом».

Причина

Гарантированное наложение в PerformPoisonedWeapom висело на боевой защелке:

if (((success) && (number(1, 100) <= 25)) ||
    (!vict->battle_affects.get(kEafFirstPoison) && !AFF_FLAGGED(vict, EAffect::kPoisoned))) {

kEafFirstPoison лежит в battle_affects, а они обнуляются и при входе в бой (fight.cpp:233), и при выходе из него (fight.cpp:306). То есть каждый новый бой для цели — «первый», и первый удар опять дает гарантию. При этом poison_affect_join стакает модификатор до трех раз и каждый раз ставит полную длительность, а сам яд помечен kAfSameTime и на мобе держится около семи минут. Выходило, что беготня туда-сюда набивает полный стак быстрее честного боя, где повторные наложения идут с шансом 25%.

Аконита это не касалось: один из его узлов имеет тип kPoisoned, поэтому AFF_FLAGGED(vict, kPoisoned) блокировал вторую половину условия. У белены, скополии и дурмана типы свои (kBelenaPoison и прочие), и вся защита держалась только на защелке.

Правка

Гарантия теперь проверяет не «первый раз за бой», а «этого яда на цели еще нет» — по опознавательному аффекту кластера:

static EAffect PoisonClusterAffect(ESpell spell_id);   // kAconitumPoison / kScopolaPoison / kBelenaPoison / kDaturaPoison
...
if (((success) && (number(1, 100) <= 25)) ||
    (!AFF_FLAGGED(vict, PoisonClusterAffect(spell_id)) && !AFF_FLAGGED(vict, EAffect::kPoisoned))) {

Проверка !AFF_FLAGGED(vict, kPoisoned) оставлена как была, так что для аконита поведение не меняется вовсе. Защелка kEafFirstPoison стала не нужна и убрана из EExtraAttackFlag — в коде на нее больше нет ни одной ссылки.

Что меняется в игре: первое наложение каждого яда по-прежнему гарантировано, повторные внутри действия яда — честные 25% за удар, и выбегание из боя этого больше не обнуляет.

Проверка

Сборка release + build_tests=true чистая, без предупреждений; юнит-тесты 796 прошли, 3 отключены.

🤖 Generated with Claude Code

…oison

Гарантированное наложение яда с оружия висело на боевой защелке
kEafFirstPoison, а battle_affects чистятся и при входе в бой, и при выходе из
него. Поэтому каждый новый бой был для цели "первым": отбежать, вернуться и
ударить -- снова гарантированный прок, и так до предельного стака, хотя сам яд
держится еще минуты. Стоя в бою повторные наложения идут с шансом 25%, то есть
беготня была выгоднее честного боя.

Теперь гарантия проверяет, висит ли на цели этот же яд: у аконита это и так
работало через узел kPoisoned, остальные три яда носят свои флаги, так что
добавлено опознание кластера по типу яда. Защелка больше не нужна и убрана.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@bylins
bylins merged commit d389b5b into master Oct 24, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant