Spectre, которая забрала все группы

Небольшой абуз, который позволяет серьезно подпортить нервы в игре, но раз фрог уж допустил такую проблему и не исправляет её уже несколько лет, почему бы и нет.
Нам понадобятся:
  •  Spectre — 1 штука;
  • 6-й уровень или выше — 1 штука;
  • Кнопка R — 1 штука;
  • 30-120 секунд, в зависимости от среднего APM.


Предыстория (механика)

В WC3, как и в любой нормальной игре, есть механизм сбора мусора. Использованные однажды объекты не должны оставаться в памяти и занимать место, если они никому не нужны. Но не все объекты одинаково хорошо удаляются, и группы юнитов — один из таких объектов.

Я не могу сказать, в чем именно проблема (потому что не пускался в тесты), но факт фактом — люди предпочитают использовать готовые системы с подготовленным массивом групп, вместо того, чтобы создавать их динамически. Грубо говоря, на старте игры сразу создаются объекты-группы, которые никогда не уничтожаются и просто используются заново. Безотходное производство.

Выглядит код очень просто:
function GG takes nothing returns group
  local integer i=GroupCounter
  loop
    exitwhen i==GroupCounter-1
    if GroupTaken[i]==false then
      set GroupCounter=i+1
      if GroupCounter==120 then
        set GroupCounter=0
      endif
      set GroupTaken[i]=true
      return Groups[i]
    endif
    set i=i+1
    if i==120 then
      set i=0
    endif
  endloop
  call DBG(AllPlayers,5.00,"|c00ff0303CRITICAL ERROR: FOUND NO AVAILABLE GROUPS|r")
  call DBG(AllPlayers,5.00,"|c00ff0303Send this replay to [email]IceFrog@gmail.com[/email]|r")
  return CreateGroup()
endfunction

где GroupCounter является указателем на последний занятый номер группы. Запрос группы превращается в перебор массива, нахождение свободной группы и передача ссылки на неё. Память чиста, производительность тоже довольна.

Еще одна функция занимается утилизацией групп. Попользовался — положи на место через эту функцию. Если её не использовать, то группа останется «занятой» навсегда — важно всегда расставлять собственные уборщики использованного.

Короче

В коде ульты Spectre фрог, как обычно, вписал условие, не подумав как следует. Уничтожение взятой группы происходит только в случае, если цель для Reality была найдена, в противном случае функция просто закрывается.

В результате за 120 применений  Reality без подходящей цели (когда на карте нет иллюзий от Spectre) можно занять все свободные группы и заставить движок генерировать новые группы. При этом в коде возникает новая проблема.

Когда функция занимает 120-ю группу, счетчик сбрасывается на 0. Но при этом в цикле ожидается, что i строго равно счетчику минус единица. И при этом i инкрементируется, и проверки на корректность условия нет. Игра просто уходит в бесконечный цикл и здесь возможно всё, что угодно.

На моей памяти у бесконечных циклов есть несколько вариантов завершения:
  1. Вызов функции пристрелит сам варкрафт через некоторое время — до выдачи группы дело не дойдет;
  2. Варкрафт пристрелит чисто цикл и продолжит выполнение функции;
  3. Варкрафт молча закроется.

В первом случае — группы нет, и все манипуляции, которые хотела провести функция с нею, обречены на провал. Это означает, что часть скилов просто перестанут работать.

Во втором случае вернется группа и всё пройдет корректно, плюс прибавится немного использованной памяти.

Ну а проблемы третьего варианта для игроков очевидны. При этом технически никакой ошибки видно не будет.



Для тех, кто еще не понял

Взять 6-й уровень Spectre и взять ульт. Использовать Reality на любое место 120+ раз. Наслаждаться экраном, наполовину погрязшим в Error-сообщениях, которые появляются заново каждый раз при обращении к группе (а они происходят постоянно).

22 комментария

avatar
gfgf
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.