Убить Рошана с одного удара - пояснение
В связи с тем, что информация о природе бага, описанного в топике про Рошана, была результатом предположений, её правдивость также находилась под вопросом. После лоботомии варкрафта Фукей сумел найти, в чем именно заключалась загвоздка игры с апгрейдами и спеллбуками. Далее приведен миниатюрный разбор ситуации by Fukkei.
Псевдокод того, как происходит добавление абилки
По коду можно понять, что если абилка — спеллбук с абилкой внутри, то UnitAddAbilityInternal вызывается 2й раз рекурсивно, что приводит, например, вот к такому результату:
Форж, exort lvl 1 (300 hp: 200 + 100), не получал урон:
Если повторить шаги для exort lvl 2+, то видно, что на степе 2 максимальное хп юнита становится 0 и меньше.
Соответственно, перерасчет текущего хп юнита возвращает ноль (берет по модулю), т.к. текущее хп не может быть больше максимального и не может быть меньше нуля.
Что получается после SetUnitState(u, UNIT_STATE_LIFE, 0), думаю, не нуждается в комментариях.
Сама функция перерасчета текущего ХП работает корректно и деления на ноль там нет — после такой операции FPU бы кинул исключение и приложение упало.
Псевдокод того, как происходит добавление абилки
class AbilityBase
{
virtual void OnAbilityAdded(UnitBase* u) = 0;
}
class SpellBook : public AbilityBase
{
std::list<AbilityBase*> _abilitiesContainer;
virtual void OnAbilityAdded(u)
{
for (auto a : _abilitiesContainer)
{
UnitAddAbilityInternal(u, a);
}
}
}
void UnitAddAbilityInternal(UnitBase* u, AbilityBase* a)
{
RemoveUnitAbilities(u);
abilTable[u->GetID()].push_back(a);
a->OnAbilityAdded(u);
RestoreUnitAbilities(u);
}
По коду можно понять, что если абилка — спеллбук с абилкой внутри, то UnitAddAbilityInternal вызывается 2й раз рекурсивно, что приводит, например, вот к такому результату:
Форж, exort lvl 1 (300 hp: 200 + 100), не получал урон:
- вызывается UnitAddAbilityInternal из jass api, добавляется спеллбук, дропается бафф от апгрейда хп, 300 — 100 = 200 макс хп, текущее хп ставится в 200 (ч-з SetUnitState UNIT_STATE_LIFE)
- вызывается UnitAddAbilityInternal из коллбэка спеллбука(OnAbilityAdded), он теперь должен добавить все свои внутренние абилки. добавляется абилка из спеллбука, опять дропается бафф ХП, 200 — 100 = 100 макс хп, текущее хп ставится в 100
- абилка внутри спеллбука добавилась, восстанавливаем баффы, 100 + 100 = 200хп
- спеллбук добавился, восстанавливаем баффы, 200 + 100 = 300хп
Если повторить шаги для exort lvl 2+, то видно, что на степе 2 максимальное хп юнита становится 0 и меньше.
Соответственно, перерасчет текущего хп юнита возвращает ноль (берет по модулю), т.к. текущее хп не может быть больше максимального и не может быть меньше нуля.
Что получается после SetUnitState(u, UNIT_STATE_LIFE, 0), думаю, не нуждается в комментариях.
Сама функция перерасчета текущего ХП работает корректно и деления на ноль там нет — после такой операции FPU бы кинул исключение и приложение упало.
7 комментариев
ну про сашу-яшу все знают, да и редко
напишите хоть кто-то, кто на DCL видел что рошан упал с одного удара и это повлияло на игру как-то!
с уважением, просто первый пост от тебя который не понял, обидно
дать вод?
Но суть бага, видимо, в том, что, при добавлении некоторых бафов, игра сначала дважды снимает бонусное HP юнита.
Зачем/кому это надо, почему айкап не может справиться с ними
И Куда пропали джас рассказы, почему нет новых выпусков?