Решили: кровотечение стакается по четвёртому правилу — StackRule.Portions: каждое наложение
заводит порцию со своей силой и своим сроком, вклады суммируются, потолка нет, каждая порция сходит
отдельно. Силу приносит накладывающий через новую перегрузку ICombatContext.ApplyEffect(..., float potency), и считается она от стата бьющего, ДО брони цели.
Почему: три прежних правила стоят на модели «одна сила и один срок на всех плюс счётчик»: сила
снимается со статов первого наложившего и рестаком не обновляется. Для крови это неверно вдвойне —
второй кровоточащий кит молча раздавал бы силу первого, а «кровотечение силой 30% от МОЕГО удара»
стало бы невыразимым. Отвергнут флаг рядом с тремя правилами: смешивать модели нельзя, порционный
эффект читает RuntimeEffect.PortionRate, обычный — ScaledPotency и VisibleStacks, и молчаливое
совпадение дало бы DoT, который бьёт то одним, то другим. Отвергнуты и отдельные ассеты крови на
каждую форму носителя: правка линии перестала бы доходить до половины носителей.
Доля берётся от стата, а не от прошедшего сквозь броню урона, потому что тик крови сам режется физбронёй — доля от уже прошедшего означала бы одну и ту же броню, применённую дважды (против танка кровь теряла бы три четверти силы). Побочно: броня цели читается живой на каждом тике, поэтому сорванная с танка защита немедленно делает кровь больнее, даже если ранивший уже мёртв.
Грабли: стаки у порционного эффекта — производная от числа порций, а не отдельный счётчик; два
числа об одном и том же разъехались бы на первом же истёкшем стаке. И вклад порций уже суммирован в
Potency, поэтому наивное «rate × стаки» в общем месте чтения стаков дало бы квадратичный урон —
правило живёт в единственной точке (MakeContext), а не в каждом компоненте. Перевод «весь урон
порции» → «урон в секунду» делится на СЕКУНДЫ её жизни, не на тики: делением на тики сила вышла бы
в тридцать раз меньше.
Владелец правды: RuntimeEffect.AddPortion / TickDownPortions, StackRule.Portions,
BleedOnHitComponent, тесты BleedLineTests.