Diablo II, дни с седьмого по одиннадцатый
Пост про пятый и шестой дни остановился 16 октября в 17:53: на карте исследования 29 строк, 28 из них после ревью, а запуск по бою, первый запуск симуляции, ещё впереди. Этот пост — об остатке того вечера и о пяти днях после него, до 21 октября, 12:11. Теперь на карте 36 строк и 35 после ревью. Единственная, которая ещё нет, снова самая новая: строка chain, добавленная 20-го, для спецификаций ядра, прогнанных одной цепочкой от сида игры до дропа на полу, без единого значения, взятого из игры по дороге.
Главное отличие от прошлых постов: я не играл. В шестой день семь сессий были моими; за эти пять дней — ни одной. Список того, что делал я, короткий: вечером 16-го я одобрил шесть планов, чтобы они шли без присмотра, 20-го — ещё пять и порядок того, что осталось, 17-го выполнил одну команду от root, чтобы показать, что файрвол и так закрывает порт игры снаружи, а без этого двух клиентов в одну игру не пускали, утвердил семь ADR, которые мне принесли, дважды ставил лейны на паузу, а 20-го попросил убрать закрытое из бэклога в архив, потому что он разросся. Всё остальное ниже сделали лейны, каждый — агент со своей копией репозитория, на харнессе, то есть на игре под отладчиком с подключённым логгером, и сделали за ночи, в которые машину выключали, она спала девять часов, потом семь, а один раз осталась без памяти.
Карта работы
Карта исследования к каждой отсечке
- не начато
- в плане
- находки
- черновик спецификации
- спецификация после ревью
3 спецификация после ревью 1 находки 1 в плане 23 не начато из 28
Ядро
- rng спецификация после ревью
- items/tc находки
- items/quality не начато
- items/affixes не начато
- items/uniques-sets не начато
- items/properties не начато
- monsters/pool не начато
- monsters/spawn не начато
- monsters/special не начато
- drlg/overview в плане
- drlg/preset не начато
- drlg/maze не начато
- drlg/outdoor не начато
- drlg/warps не начато
- objects не начато
Опоры
- data/excel спецификация после ревью
- data/calc не начато
- data/strings не начато
- rng/seeds спецификация после ревью
- drlg/collision не начато
- save/d2s не начато
Пути создания
- items/vendors не начато
- items/cube не начато
- items/sockets-runewords не начато
- items/quest-drops не начато
- monsters/stats не начато
- hirelings не начато
- player/creation не начато
28 спецификация после ревью 1 в плане из 29
Ядро
- rng спецификация после ревью
- items/tc спецификация после ревью ↑
- items/quality спецификация после ревью ↑
- items/affixes спецификация после ревью ↑
- items/uniques-sets спецификация после ревью ↑
- items/properties спецификация после ревью ↑
- monsters/pool спецификация после ревью ↑
- monsters/spawn спецификация после ревью ↑
- monsters/special спецификация после ревью ↑
- drlg/overview спецификация после ревью ↑
- drlg/preset спецификация после ревью ↑
- drlg/maze спецификация после ревью ↑
- drlg/outdoor спецификация после ревью ↑
- drlg/warps спецификация после ревью ↑
- objects спецификация после ревью ↑
Опоры
- data/excel спецификация после ревью
- data/calc спецификация после ревью ↑
- data/strings спецификация после ревью ↑
- rng/seeds спецификация после ревью
- drlg/collision спецификация после ревью ↑
- save/d2s спецификация после ревью ↑
Пути создания
- items/vendors спецификация после ревью ↑
- items/cube спецификация после ревью ↑
- items/sockets-runewords спецификация после ревью ↑
- items/quest-drops спецификация после ревью ↑
- monsters/stats спецификация после ревью ↑
- hirelings спецификация после ревью ↑
- player/creation спецификация после ревью ↑
Симуляция
- combat/formulas в плане
32 спецификация после ревью 3 находки из 35
Ядро
- rng спецификация после ревью
- items/tc спецификация после ревью
- items/quality спецификация после ревью
- items/affixes спецификация после ревью
- items/uniques-sets спецификация после ревью
- items/properties спецификация после ревью
- monsters/pool спецификация после ревью
- monsters/spawn спецификация после ревью
- monsters/special спецификация после ревью
- drlg/overview спецификация после ревью
- drlg/preset спецификация после ревью
- drlg/maze спецификация после ревью
- drlg/outdoor спецификация после ревью
- drlg/warps спецификация после ревью
- objects спецификация после ревью
Опоры
- data/excel спецификация после ревью
- data/calc спецификация после ревью
- data/strings спецификация после ревью
- rng/seeds спецификация после ревью
- drlg/collision спецификация после ревью
- save/d2s спецификация после ревью
- drlg/lifecycle спецификация после ревью
Пути создания
- items/vendors спецификация после ревью
- items/cube спецификация после ревью
- items/sockets-runewords спецификация после ревью
- items/quest-drops спецификация после ревью
- monsters/stats спецификация после ревью
- hirelings спецификация после ревью
- player/creation спецификация после ревью
Симуляция
- combat/formulas спецификация после ревью ↑
- stats/aggregate спецификация после ревью
- stats/states спецификация после ревью
Правила игры
- quests/progression находки
- quests/travel находки
- items/economy находки
35 спецификация после ревью 1 находки из 36
Ядро
- rng спецификация после ревью
- items/tc спецификация после ревью
- items/quality спецификация после ревью
- items/affixes спецификация после ревью
- items/uniques-sets спецификация после ревью
- items/properties спецификация после ревью
- monsters/pool спецификация после ревью
- monsters/spawn спецификация после ревью
- monsters/special спецификация после ревью
- drlg/overview спецификация после ревью
- drlg/preset спецификация после ревью
- drlg/maze спецификация после ревью
- drlg/outdoor спецификация после ревью
- drlg/warps спецификация после ревью
- objects спецификация после ревью
- chain находки
Опоры
- data/excel спецификация после ревью
- data/calc спецификация после ревью
- data/strings спецификация после ревью
- rng/seeds спецификация после ревью
- drlg/collision спецификация после ревью
- save/d2s спецификация после ревью
- drlg/lifecycle спецификация после ревью
Пути создания
- items/vendors спецификация после ревью
- items/cube спецификация после ревью
- items/sockets-runewords спецификация после ревью
- items/quest-drops спецификация после ревью
- monsters/stats спецификация после ревью
- hirelings спецификация после ревью
- player/creation спецификация после ревью
Симуляция
- combat/formulas спецификация после ревью
- stats/aggregate спецификация после ревью
- stats/states спецификация после ревью
Правила игры
- quests/progression спецификация после ревью ↑
- quests/travel спецификация после ревью ↑
- items/economy спецификация после ревью ↑
Стрелка отмечает строку, которая сдвинулась с прошлого снимка. Источник: docs/specs/README.md на коммитах 8faba4f2, 33dc648, 02d790d и 483728e. Полоса «Правила игры» добавлена вечером 16 октября решением ADR-0017; строка chain — планом 0048 20-го.
Показать таблицей
| Подсистема | День 1 | День 6 | День 8 | День 11 |
|---|---|---|---|---|
rng | спецификация после ревью | спецификация после ревью | спецификация после ревью | спецификация после ревью |
items/tc | находки | спецификация после ревью | спецификация после ревью | спецификация после ревью |
items/quality | не начато | спецификация после ревью | спецификация после ревью | спецификация после ревью |
items/affixes | не начато | спецификация после ревью | спецификация после ревью | спецификация после ревью |
items/uniques-sets | не начато | спецификация после ревью | спецификация после ревью | спецификация после ревью |
items/properties | не начато | спецификация после ревью | спецификация после ревью | спецификация после ревью |
monsters/pool | не начато | спецификация после ревью | спецификация после ревью | спецификация после ревью |
monsters/spawn | не начато | спецификация после ревью | спецификация после ревью | спецификация после ревью |
monsters/special | не начато | спецификация после ревью | спецификация после ревью | спецификация после ревью |
drlg/overview | в плане | спецификация после ревью | спецификация после ревью | спецификация после ревью |
drlg/preset | не начато | спецификация после ревью | спецификация после ревью | спецификация после ревью |
drlg/maze | не начато | спецификация после ревью | спецификация после ревью | спецификация после ревью |
drlg/outdoor | не начато | спецификация после ревью | спецификация после ревью | спецификация после ревью |
drlg/warps | не начато | спецификация после ревью | спецификация после ревью | спецификация после ревью |
objects | не начато | спецификация после ревью | спецификация после ревью | спецификация после ревью |
chain | — | — | — | находки |
data/excel | спецификация после ревью | спецификация после ревью | спецификация после ревью | спецификация после ревью |
data/calc | не начато | спецификация после ревью | спецификация после ревью | спецификация после ревью |
data/strings | не начато | спецификация после ревью | спецификация после ревью | спецификация после ревью |
rng/seeds | спецификация после ревью | спецификация после ревью | спецификация после ревью | спецификация после ревью |
drlg/collision | не начато | спецификация после ревью | спецификация после ревью | спецификация после ревью |
save/d2s | не начато | спецификация после ревью | спецификация после ревью | спецификация после ревью |
drlg/lifecycle | — | — | спецификация после ревью | спецификация после ревью |
items/vendors | не начато | спецификация после ревью | спецификация после ревью | спецификация после ревью |
items/cube | не начато | спецификация после ревью | спецификация после ревью | спецификация после ревью |
items/sockets-runewords | не начато | спецификация после ревью | спецификация после ревью | спецификация после ревью |
items/quest-drops | не начато | спецификация после ревью | спецификация после ревью | спецификация после ревью |
monsters/stats | не начато | спецификация после ревью | спецификация после ревью | спецификация после ревью |
hirelings | не начато | спецификация после ревью | спецификация после ревью | спецификация после ревью |
player/creation | не начато | спецификация после ревью | спецификация после ревью | спецификация после ревью |
combat/formulas | — | в плане | спецификация после ревью | спецификация после ревью |
stats/aggregate | — | — | спецификация после ревью | спецификация после ревью |
stats/states | — | — | спецификация после ревью | спецификация после ревью |
quests/progression | — | — | находки | спецификация после ревью |
quests/travel | — | — | находки | спецификация после ревью |
items/economy | — | — | находки | спецификация после ревью |
Семь строк новые. Две — вторая фаза симуляции, характеристики и состояния. Одна — жизненный цикл комнат, опора, о которой никто не вспоминал, пока запуск по циклу не показал, что усыплённая и разбуженная комната создаёт предметы заново. Три — новая полоса, правила игры: продвижение по квестам, перемещения и экономика предметов, две области, которые второе решение проекта в первый же день оставило за рамками. И одна — цепочка.
Каждая строка прошла те же стадии, что и раньше: статическое чтение кода с пометкой [I], запуск на харнессе под отладчиком, который поднимает воспроизведённое до [C], спецификация, ревью агентом, который её не писал. Запуски за это время:
| Запуск | Что воспроизвела модель | Расхождений |
|---|---|---|
| Бой | 40 логов, 40 655 событий атак и эффектов при попадании, сцепленных по сидам | 0 |
| Характеристики и состояния | 18 сессий; 891 844 чтения характеристик, 3 643 наложения состояний, 54 719 тиков регенерации | 0 |
| Жизненный цикл комнат | 13 сессий, 2 215 807 проверок; 2 440 усыплений комнат и 1 362 пробуждения | 0 |
| Цикл комнат, монстр идёт за игроком | 3 сессии на Hell, 675 849 проверок | 4, объяснены |
| Квесты и перемещения, три запуска | 45 сессий, 45 714 проверок | 0 |
| Экономика, два запуска | 33 901 вызов расчёта цены, 1 061 бросок прочности, 1 412 событий износа, 14 воскрешений | 0 |
| Два клиента | 19 сессий с двумя настоящими клиентами игры; 417 убийств в группе, 385 делений опыта, 230 атак игрока на игрока | 0 |
| Недоборы симуляции | 31 лог боя, 18 737 событий; 10 логов характеристик; 1 лог перемещений | 0 |
| Объекты, ревизия | 22 сессии, 234 315 проверок | 0 у модели |
| Предметы, три пакета ревизии | 35 сессий; 873 вызова treasure class, 1 043 создания, 1 078 выборов метательного оружия | 0 |
| Навыки, одиннадцать пакетов в эмуляторе | 99 450 случаев функций навыков и снарядов, прогнанных в дизассемблере без игры | 0 |
| От сида к миру, запуск 1 | 28 логов, 156 уровней, 9 057 объектов, 1 286 предметов из одного сида игры | 2, открыты |
Проверка здесь — одно значение, которое модель предсказала, а игра записала в лог. Treasure class, который в таблице встречается дважды, — это строка таблицы дропа, по которой бросает монстр или сундук. Сессии вели агенты по скриншотам, пилотом из четвёртого дня, кроме одиннадцати пакетов по навыкам: те шли в эмуляторе, о котором писал пост про шестой день, по правилу, которое 20-го расширили, об этом ниже.
Запуск по бою
Шестой день закончился тем, что формулы боя были прочитаны в коде, а запуск на харнессе ещё ждал. Его приняли 16-го в 19:26, через полтора часа после отсечки того поста: 19 сессий, 15 358 событий, ноль расхождений. В плане стояло 2 000 атак игрока, вышло 2 030; 1 000 атак монстров, вышло 4 533, потому что монстры много промахиваются: 697 попаданий против 3 836 промахов, из них 2 243 заблокированы. Каждый вид событий нужно было сцепить: сид на входе второго события предсказывается по выходу первого, не меньше двадцати пар на вид, и «каждый вид проходит порог в 20 с обоих концов».
До чего первая партия не дотянулась — до Andariel на Hell: лейну не хватило времени, две попытки, и так и записано. Недоборы взял лейн-продолжение, и в тот же вечер он остановился на «сроке владельца для машины». Он закончил к 07:56 следующего утра: 40 логов, 40 655 событий, по-прежнему ноль расхождений, и три вещи, для которых нужен был босс. Crushing blow по боссу акта, 34 события на Andariel, — одна восьмая, как и прочитано; по суперуникальным, 55 событий, тоже одна восьмая; а процент урона наёмника по ней — 50 на Normal, 35 на Nightmare и 25 на Hell, одно значение из таблицы, по номеру сложности, и именно 25 на Hell отличает этот столбец от соседнего, где стоит 20.
Запуск поймал чтение на ошибке. В чтении было сказано, что open wounds по боссу акта кровоточит в полную силу, и в спецификации тоже. А чекер был написан по проверке из кода, которая делит кровотечение пополам для любого монстра с флагами типа 0x0C, и у Andariel стоит 0x08, флаг уникального. Все 63 её open wounds были поделены пополам. Словами ревью: «„нет /2 для босса“ в находке и „боссы акта получают полную величину“ в спецификации были ошибкой, а чекер всё это время моделировал правильно». Спецификация закрылась 17-го в 08:16: 190 подтверждённых утверждений против 139 выведенных, и четыре утверждения сообщества, которые в шестой день были опровергнуты чтением, бонус класса к уровню, лечение от поглощения, crushing blow по уникальным и его зависимость от числа игроков, теперь опровергнуты запуском. Запуск по недоборам через три дня добавил чемпионов: «52 crushing blow по чемпионам сняли 1/4». Не одну восьмую.
Один монстр в модель не вписался: сессия с Fleshripper, уникальным ножом, который не даёт монстрам лечиться, оставила 101 расхождение, все в обработчике убийства, который работает в той же функции, что наносит урон, и который никто не читал. Сессию отложили, а обработчик ушёл в план по навыкам, и 20-го чтение нашло, где накладывается состояние ножа: в ветке, где бросок на попадание удался, между попаданием и блоком.
Кинжал, который сломал модель
-
Fleshripper: его состояние «не лечиться» накладывается между попаданием и блоком
Лист предмета из инструмента проекта tools/item_art.py: картинка из инвентаря и кадры падения предмета на землю. Графика Diablo II © Blizzard Entertainment.
Характеристики и состояния
Вторую фазу симуляции одобрили вечером 16-го, а закрылась она 17-го в 20:06. Это та часть игры, которая всё суммирует: как бонус предмета доходит до силы того, кто его носит, и как состояние с таймером, благословение святилища, аура, проклятие, накладывается, обновляется и истекает. Восемнадцать сессий с шестью персонажами, собранными инструментами, ноль расхождений, и числа такие, какие даёт прогон дерева: 891 844 чтения характеристик в залогированных окнах, 232 042 записи в кеш, 17 634 проверки требований, 3 643 наложения состояний, из них 2 608 — обновление уже наложенного, и 6 207 длительностей аур, каждая равна задержке ауры плюс один.
Статическое чтение утверждало, что ни одна функция этой фазы не берёт случайного числа, и план превратил это в проверку: сид пишется в лог на входе и на выходе каждого вида событий. Один вид число взял. Аура с уроном, Sanctuary, берёт «одно RNG_RangeB на попадание», так что её проверили сцеплением, 746 пар. 21-го каталог уточнил: одно число на один прогон ауры, сколько бы юнитов она ни задела; пока только [I].
Три вещи из спецификации, которых игрок не угадал бы. Бонус предмета «за уровень», тот, что растёт с уровнем персонажа, «не обновляется, когда носитель получает уровень», 94 записи, подтверждено; он пересчитывается, когда предмет переложили. От эфирной скидки к требованиям, десять единиц, в запуске зависели 30 проверок: персонаж с силой от 115 до 124 против War Boots, которым нужно 125. А пересчёт всего дерева запускается каждые 136 кадров без всякого действия игрока; что его ставит в очередь, не прочитано. Справочник сообщества пишет, что операция 6 над характеристиками «не работает», а операция 7 обновляется только на клиенте; сервер считает обе, просто ни один стандартный предмет до них не доходит, потому что два аффикса, которые ими пользуются, не могут появиться. Ревью ещё вычеркнуло из чтения число «96 с при 25 кадрах в секунду» для святилища: правило проекта с шестого дня — время только в кадрах и ни в чём другом.
Комнаты, которые спят
В посте про шестой день жизненного цикла комнат нет, потому что о нём никто не вспоминал. Игра усыпляет комнату, когда рядом нет игрока, и будит, когда он возвращается, а пробуждение восстанавливает юниты: заново создаёт монстров, объекты и предметы по записям, которые она сохранила. Любая реализация обязана делать это так же, иначе игрок, который отошёл и вернулся, найдёт другую комнату. План одобрили 16-го в 21:15, и его запуск 17-го стал самым большим за эти дни: 13 сессий, 2 215 807 проверок, 2 440 комнат усыплены и 1 362 разбужены, 2 035 монстров возвращены, у каждого ровно та жизнь, которую предсказала модель.
Чтение кода ошиблось в четырёх местах, вот три из них. Восстановление предмета берёт два числа с сида игры, а простой предмет возвращается с нулевым начальным сидом. Визит игрока между двумя проходами усыпления не сбрасывает счётчик простоя. А главный сюрприз чтения, мёртвый чемпион, сохранённый и возвращённый живым, оказался невозможен: «Маска 0x18 в проверке сохранения — это „особый или миньон“. У каждого залогированного чемпиона стоит 0x08, так что мёртвый чемпион не сохраняется никогда».
С сообществом спецификация цикла комнат расходится как раз в том, что игроки повторяют часто. Про уровень без флага SaveMonsters говорят, что он оставляет монстров «ранеными»; в 1.14d «любой другой живой монстр усыплённой комнаты освобождается без записи, а комната заново не заселяется, так что он исчезает, а не ранен». Про Blood Raven говорят, что через двадцать минут она снова с полным здоровьем; правило такое: восстановленный монстр сохраняет записанную жизнь, если между сохранением и восстановлением прошло меньше 7 500 кадров, иначе получает максимум. А Prevent Monster Heal якобы сбрасывается, если отойти слишком далеко: по расстоянию не сбрасывается ничего, «усыплённый и разбуженный монстр — это новый юнит».
Монстр, о котором ходит правило двадцати минут
-
Blood Raven, как игра рисует её класс
Собрано из слоёв спрайтов самой игры инструментом tools/cof.py: первый кадр спокойной позы с луком, без смены цвета, которую суперуникальный получает в игре. Графика Diablo II © Blizzard Entertainment.
Один случай запуск не достал: монстр, который идёт за игроком в город. Пакет-продолжение попробовал три сессии на Hell 17-го и закончил 18-го: 675 849 проверок и единственное ненулевое число расхождений у законченного запуска за эти дни, четыре. Все четыре объяснены одинаково: бит флага, который восстановление не копирует обратно, четыре записи из 1 689. Преследователь ни разу не прошёл через город, и прогон по 106 раскладкам городов без игры показал, почему это невозможно: из 93 944 пар клеток ни один маршрут через город не короче, потому что «внутренность каждого города встречается с соседним уровнем в одних воротах». Пакет заодно вычитал, что уборка истёкших предметов идёт каждые 1 500 кадров, а не каждые 20, как было в чтении; 20 — это таймер квестов рядом. Это остаётся выведенным: запуск исключает 20, не подтверждая 1 500.
У запуска был сбой, и сбой стал правилом. Один запуск игры наложился на идущую сессию разработки на том же слоте харнесса, убили обоих, а частичный лог наложившегося запуска удалили. Теперь в руководстве по игре на харнессе написано: «Частичные логи сохраняются. Прерванная сессия или сессия, которая наложилась на другую на том же слоте, оставляет частичный лог: хранить его… и никогда не удалять». А третью сессию на Hell убили 17-го в 21:38, когда машина выключилась посреди её второго захода, ухода из комнаты и возвращения; её частичный лог вошёл в запись, а черновик лейна, лежавший во временной папке, пропал, и его переписали по якорям.
Ревизия
В шестой день появился план 0038: ревизия 1 526 выведенных утверждений, которые ещё оставались в спецификациях после ревью, разложенных по пакетам: статическим, где доказательство уже лежит в сохранённом логе или во втором источнике, и пакетам на харнессе, которым нужны новые сессии. К отсечке того поста прошли два пакета. За эти дни прошли ещё восемнадцать.
Два пакета шли не в игре, а в эмуляторе, способом, который ADR-0015 разрешил в шестой день: одна функция бинарника за раз, в эмуляторе процессора из Ghidra, на входах, которые выбрал пакет, с трассировкой каждого чтения памяти. Первый прогнал 28 643 случая по десяти семействам функций, и каждый сошёлся бит в бит, а отрицательный контроль упал, как и должен. Второй добавил 18 800 случаев и директиву guard: случай, у которого счётчик команд доходит до фатального пути, останавливается, а не блуждает дальше. Он же нашёл предел самого эмулятора: по его модели команд деление наименьшего 32-битного целого на минус единицу возвращает ноль там, где настоящий процессор уходит в исключение. «Это не меняет ни одного решения, так что владельцу ничего не выносим».
Два утверждения вернулись опровергнутыми. В спецификации сидов было сказано, что сид от 2³¹ и выше задаётся в командной строке своим отрицательным десятичным значением. Запуск показал, что парсер копирует текст ключа только до следующего дефиса, так что -seed -1 приходит пустым, читается как ноль, и игра берёт часы; значение от 2³¹ и выше обрезается до максимума. Из командной строки воспроизводимы сиды от 1 до 0x7FFFFFFF. А в спецификации Куба было написано, что поиск места для коровьего портала берёт число; не берёт, число берёт объект портала, 171, 173 и 171 шаг в трёх открытиях. Пакет по treasure class нашёл именно такое завышение, ради которого ревизия и нужна: ограничитель в броске качества, про который в заметке к шагу стояло «ни разу не сработал в запусках», срабатывает в 667 бросках пакета и в 138 меняет результат. Заметка была верна для двух запусков по качеству, на которых её написали неделей раньше.
Когда пакеты спецификации легли, её перетегируют и пересчитывают шапку:
Опись на отсечке: 567 утверждений в статических пакетах, 526 в пакетах на харнессе, 414 заблокированы и 17 подняты самой описью. Из заблокированных у 288 до доказательства не добраться, 73 нужна подменённая таблица, 28 нужна симуляция, 7 нужны два игрока в одной игре и 10 нужна моя игра. В шестой день впереди был двадцать один пакет на харнессе; осталось двенадцать, в порядке, который я задал 20-го: сначала ядро и опоры.
Правила игры
Второе решение проекта в первый день очертило рамки вокруг создания: предметы, монстры, уровни. Шестой день добавил симуляцию. Вечером 16-го третье решение, ADR-0017, добавило то, что в ADR названо правилами игры, две области и три строки на карте, вне порядка фаз симуляции: продвижение по квестам с перемещениями и экономика предметов. Довод: «Реализация, в которой есть каждый путь создания, но нет продвижения по квестам, вейпоинтов и цен, — это не игра, в которую можно играть, и именно на эти дыры тот, кто переписывает игру, натыкается в первую очередь после генератора мира». Правило о доказательствах зависит от формы утверждения. Функция, которая считается один раз, цена, стоимость починки, количество золота, воспроизводится так же, как путь создания; изменение по событию, бит квеста после убийства, очко прочности после удара, воспроизводится по событиям по правилу симуляции. И ADR называет цену: «Квесты зашиты в код. Таблицы квестов нет; 1.14d встраивает колбэки каждого квеста прямо в код».
Квесты и перемещения
Три запуска, 17-го, 18-го и 19-го: 11, 21 и 13 сессий, 45 714 проверок, ноль расхождений. В статическом чтении квестов 596 символов, а спецификация, которая из него вышла, самая «выведенная» на карте, 322 выведенных против 117 подтверждённых, потому что колбэки каждого квеста — это код, и очень многих колбэков ни одна сессия не коснулась.
Что решили запуски. Портал в город берёт три числа, а не пять, как было в чтении: «Оба конца выходят из SUnitCreate уже в своём режиме… так что числа не берёт ни создание, ни следующий за ним SetMode». Дверь на Arreat Summit читает один байт, личный бит квеста 35 «выполнено в этой игре», и не пустила обоих персонажей, собранных для проверки: одного с пустым словом квеста, другого со всеми выполненными квестами. Обработчик квеста 11 пишет бит в слово квеста 12, пока квест 11 выключен, 44 записи. Камни Тристрама нужно трогать в определённом порядке, и порядок — это число с сида квестов, взятое один раз за игру при первом использовании расшифрованного свитка. Перемещение Tyrael в Harrogath — не строка в его меню: в стандартном меню строки перемещения нет, а перемещает объект портала рядом с ним. А задержка после объявления враждебности, которую сообщество называет десятью секундами на выход из города: «подтвердилось для вейпоинтов (10 000 мс), опровергнуто для порталов: ворота портала ждут 5 000 мс».
Две вещи о методе. Ревью третьего запуска понизило строки меню, подтверждённые по скриншоту: «Скриншота для [C] недостаточно». А ночь с 18-го на 19-е стала первой из плохих ночей этих дней: машина ушла в сон примерно на девять часов, игра закрылась, а драйвер продолжал кликать в окно, которого больше не было, пока главная сессия не убила его в 07:23. Теперь у каждой сессии есть сторожевой таймер.
В первом запуске до Hell не дошла ни одна сессия: «скриптовый проход к городскому вейпоинту не удался в пяти запусках на Hell». В третьем дошли две. Ни один вейпоинт не был активирован из спящего состояния, потому что каждый вейпоинт, который встретили сессии, уже был активен. А шаги с боссами в квестах, убийства, которые переключают биты квеста, отмечены как кандидаты на мою игру с пометкой «По-прежнему необязательно». Я их не сыграл.
Экономика
Покупка, продажа, gamble, починка, наём и воскрешение наёмника, золото на полу и золото, потерянное при смерти, и износ предметов в бою. Запуск начался 17-го, переходил из лейна в лейн и закрылся 19-го: 26 525 вызовов расчёта цены по 3 762 различным входам, 138 сумм «починить всё», 22 найма, 14 воскрешений, из них в 4 отказано, 20 потерь при смерти, 1 061 бросок прочности и 1 412 событий износа, ноль расхождений. Второй запуск в тот же день добавил 7 376 вызовов расчёта цены для случаев, которые первый пропустил: крафтовые предметы, починка на Hell, gamble на 3-м уровне.
Спецификация экономики сверила с кодом 22 утверждения сообщества:
Опровергнутые:
- Эфирный предмет продаётся на 25 процентов дешевле. Он продаётся за четверть: цена продажи сдвигается вправо на два бита. Классовый предмет делится на четыре ещё раз.
- Эфирное метательное оружие всегда стоит одну монету. Стопка эфирных дротиков ушла за 1 040 у каждого из пятнадцати торговцев.
- Множитель цены у аффикса считается в долях от 1 024 при покупке и от 4 096 при продаже. Все три значения делятся на 1 024.
- Столбец
gamble cost— это цена gamble. Он читается только для колец, амулетов и предметов версии 0; любая другая цена gamble вычисляется. - Броня изнашивается по весам слотов 2, 3, 2, 1, 1, 1 для головы, тела, щита, пояса, ног и рук. В таблице в бинарнике семь слотов с весами 3, 5, 4, 4, 2, 2, 2, и 964 из 964 выборов износа в запуске назвали слот, чей предмет потом и изнашивался.
Что подтвердилось точно: 4 процента на износ оружия и 10 на износ брони за удар, потеря при смерти в min(L, 20) процентов с сохранением 500 золотых за уровень в одиночной игре, цена воскрешения L² / 2 × 15 с потолком в 50 000. И «„Sell mult“ — это цена покупки». Есть функция, которая берёт деньги за лечение, и её никто не вызывает: 1.14d лечит бесплатно. В одном чтение кода ошиблось, и первая же проверка это поймала на четырёх провалившихся воскрешениях: отказанное воскрешение ничего не берёт и никого не воскрешает, чего в находке не было. И деталь клиента, которую запуск заметил по дороге: он спрашивает «Repair… Gold: cost — Yes / No», даже когда заплатить нечем.
Золото, которое пересчитал запуск по экономике
-
Wirt's Leg: под ней запуск насчитал 18 кучек золота и воспроизвёл каждую
Из tools/item_art.py. Второй запуск по экономике проверил золото, которое падает с тела Wirt: число кучек и уровень предмета у каждой. Графика Diablo II © Blizzard Entertainment.
Два игрока в одной игре
ADR-0008, харнесс на два клиента, висел в статусе «предложен» со второго дня, а принят был 16-го, с одним условием: прежде чем какая-либо сессия создаст игру, лейн убеждается, что порт 4000, порт игры, недоступен снаружи машины, и записывает, как проверял. Это и была моя единственная команда от root за эти дни, 17-го. Запись цитирует вывод ufw status verbose построчно, «Default: deny (incoming)», единственные разрешённые порты, и заканчивает: «Ни одно правило не называет 4000, ни один диапазон его не содержит, и у каждого правила указан порт. Значит, TCP 4000 отбрасывается на каждом интерфейсе, кроме loopback… Условие ADR-0008 выполнено». В запросе лейна было сказано: «Больше ничего не просим: ни зонда снаружи, ни второй машины».
Сам запуск был 20-го: 19 сессий с двумя настоящими клиентами на двух слотах харнесса, причём второго игрока вели по логу первого, потому что у второго нет отладчика; 417 убийств в группе с дропом, 46 событий ассортимента торговца при двух игроках, 385 делений опыта, 12 записей квестовых битов при обоих игроках в игре, 230 атак одного игрока на другого, у каждого чекера ноль расхождений. Четыре раза чекер пришлось менять, и каждый раз ревью постановило: «ошибался чекер, а не игра»; в одном был зашит один игрок. Что нашли два клиента, чего один не мог: доля опыта в группе считается 80-битным произведением доли и уровня с плавающей точкой, без округления до 32 бит, и 98 входов разводят эти два варианта; стандартный клиент не даёт объявить враждебность вне города; у мёртвого игрока свой режим, 17.
Ревью нашло и то, что скрипт, проверявший файрвол перед каждой сессией с открытием игры, всегда завершался с нулём, так что проверка, в которую он был встроен, не остановила бы ни одной сессии. Теперь он падает при любой ошибке, а по правилу его нельзя вызывать без || exit 1. Перетегирование подняло 28 утверждений по одиннадцати спецификациям, случаев с двумя игроками, которые ревизия держала заблокированными, стало 7 вместо 14, и план закрылся 20-го в 15:23. Четыре случая, где два игрока нужны у босса, оставлены мне, «Ничего не блокируют».
Навыки, в двух планах
Третья фаза симуляции — навыки и снаряды, и она больше двух первых вместе: 357 навыков, 64 различные стартовые функции и 138 функций действия на сервере, 684 строки снарядов со своими функциями движения, попадания и урона. ADR-0020, принятый 20-го, делит её надвое: «Если читать ADR-0014 буквально, он держал бы ИИ монстров (фазу 4), пока у каждой из этих функций не появится спецификация после ревью». План 0045 — машинерия, диспетчеризация, сетевые пакеты, снаряды и обработчики событий, и его спецификация считается спецификацией фазы; план 0046 — каталог каждой нумерованной функции, и он идёт рядом с четвёртой фазой, не блокируя её. В тот же день я поменял местами фазы четыре и пять: анимация и тайминг кадров раньше ИИ монстров, «потому что таймингу навыков и боя сначала нужны счётчики кадров».
Статическая фаза машинерии закрылась 20-го. Прогрессивное добивание число с сида не берёт, а подглядывает: сид сохраняется и восстанавливается. Из 61 утверждения сообщества о навыках и снарядах 27 подтвердились, 25 подтвердились с уточнением, 5 опровергнуты и 4 не покрыты, всё по чтению кода и с пометкой «выведено», с оговоркой в находке: расхождение с источником сообщества «может быть изменением из Resurrected». Опровергнутая пятёрка, теперь каждое — случай для фазы на харнессе: уровень поднятого скелета — не уровень заклинателя, а min(max(L × 3/4 + уровень навыка, 1), L); скорость снаряда — (VelLev × lvl) / 8 + Vel, сдвинутое влево на восемь, а не Vel плюс VelLev за уровень; Accel прибавляется на каждом пятом шаге пути, а не каждый кадр; у LevRange нет минус единицы; а снаряд, который промахнулся с пробиванием, освобождается на этом юните, а не летит дальше.
Каталог — это 310 записей, и идёт он в эмуляторе, потому что функцию, создающую снаряд, нельзя тысячу раз прогнать в игре с выбранными входами, а в эмуляторе можно. Пятнадцать пакетов; к отсечке приняты одиннадцать, 230 записей из 310, 99 450 случаев, ноль расхождений. Первую сессию пакета по амазонке убил менеджер памяти до проверки; сохранённый прогон — второй.
После первого пакета понадобился ADR. Большинство функций каталога кончаются вызовом, входы которого нельзя объявить: выделение юнита, планировщик пути, спавн монстра, и лейн останавливал свои случаи на этом вызове и заявлял только то, что происходило до вызова. Ревью решило, что это «не отвечает ADR-0015 (1) и (3) в том виде, как они написаны», оставило утверждения пакета на «выведено» и написало для меня ADR-0021: случай может заканчиваться на наблюдаемой границе, входе в названную вызываемую функцию, где эмулятор останавливается перед первой командой и записывает регистры, стек и память, а на то, что после вызова, утверждение не распространяется: «ничего после вызова». Отвергнутый вариант: прочитать старое правило так, будто оно это уже разрешает, «расширять правило о доказательствах толкованием — дело ADR, а не ревью». Я принял его 20-го в 14:56, и утверждения пакета перешли в подтверждённые без повторного прогона.
Что эмулятор нашёл такого, чего чтение не видело: функция действия у Fend, Zeal и Fury «возвращает 0 на каждом пути»; две стартовые функции передают ноль как attack rating в проверку попадания в ближнем бою, так что бонус Power Strike к попаданию до неё не доходит; бросок стихийного урона у одной функции делается один раз за прогон, а не на каждый юнит, тогда как в спецификации характеристик стояло «на попадание»; попадание Blade Fury создаёт снаряд класса 0, а это стрела; снаряды-кольца никогда не проверяют счётчик шагов, так что счётчик ноль не заканчивается никогда. И одно для паладинов: функция, которую Raise Skeleton и Revive выполняют раньше всего остального, «бьёт заклинателя-игрока класса 3 на maxhp / 8», а класс 3 в порядке классов — паладин; выведено: ни один случай не прогнал это с паладином.
От сида к миру
Каждую спецификацию ядра проверяли с оракулами на границах: там, где значение порождает другая спецификация, его брали из игры, а не предсказывали. Запуск по treasure class читал сид монстра из лога; запуск по дропу читал сид предмета. Так и задумано, ADR-0004, и это оставило вопрос, которого планы никогда не задавали: стыкуются ли спецификации друг с другом? План 0048 его задаёт. Его фаза 0 пересчитала оракулы по спецификациям ядра, 31, и десять из них решила убрать. Фаза 1 убрала восемь: модификаторы посохов, сид юнита после создания, монстров окна пресетов, одну функцию объектов, юниты одного пути расстановки, сид другой комнаты как состояние цепочки, сиды золотых предметов, дроп объекта. Два не получилось: один читается и по-прежнему логируется, один назван и не смоделирован. Инструмент, который гонит цепочку, называется tools/chain.py.
Планка фазы 2 — первое место, где проект требует всё сразу: «2 000 заселений комнат от сида игры до конца (без оракула сида в окне); 300 созданий объектов; 100 особых монстров…; 500 дропов, предсказанных от залогированного сида умирающего юнита через treasure class, качество, аффиксы, уникальность или сет и броски свойств без оракула сборщика». Запуск 1 начался 20-го и шёл всю ночь. Одну сессию оборвало в 20:12, когда менеджер памяти убил агента лейна вместе с драйвером, а игра шла дальше без пилота, пока её не остановил таймер. Другая пережила семичасовой сон машины и прошла проверку без расхождений. Итог: 28 логов, 26 проходят, 156 уровней каждого типа генератора в каждом акте и на каждой сложности, 9 057 объектов, 44 группы чемпионов и 110 уникальных со 147 бросками модификаторов, 849 дропов с монстров с 951 предметом, 2 514 вызовов treasure class и 1 286 созданий предметов, ни одного провала. В двух логах по одному расхождению в модели объектов, и собственное объяснение лейна было ошибочным; по чтению ревью, оба кандидата — монстры, созданные заново после того, как их комнату усыпили и разбудили, «у пересозданных нет строки CM и нет смоделированной отметки». До планки не хватило: 1 222 заселения из 2 000, это ещё около шестнадцати сессий. Запуск 2 сейчас на слоте 1. Строку chain добавили в полосу ядра на ревью фазы 0, поэтому на карте одна строка без ревью.
flowchart TB gs["сид игры"] --> lv["сиды и раскладки уровней: drlg/overview, preset, maze, outdoor, warps"] lv --> ob["объекты, сундуки и святилища: objects"] lv --> pop["заселение комнат: monsters/pool, spawn, special, stats"] pop --> kill["монстр умирает: его залогированный сид"] kill --> tc["treasure class и NoDrop: items/tc"] tc --> q["качество: items/quality"] q --> af["аффиксы, уникальные и сеты, свойства"] af --> floor["предмет на полу со своими характеристиками"]
Как это было организовано
Лейны шли как в шестой день: не больше двух лейнов на харнессе, на слотах 1 и 2, слот 0 мой, не больше двух статических лейнов с Ghidra, у каждого лейна своя копия репозитория, ревью архитектором в порядке поступления, и правило с 20-го: фазу, чьё предусловие ещё не легло, пропускают, а не ждут. Что изменилось — ревью теперь считают. 17-го появился журнал: по строке на лейн и по строке на ревью от проверяющего агента, которого проект называет архитектором: токены, вызовы инструментов, минуты, вердикт и правки по категориям. За эти дни в нём 121 строка лейнов и 107 ревью. Два вердикта — «принято» без оговорок, шесть лейнов влиты без ревью: пять учётных и один по моей просьбе, ни одного «отклонено», остальные 113 — «принято с правками», всего 514 правок.
У журнала есть назначение помимо счёта: каждые несколько ревью проверяющий читает его последние строки и превращает любую правку, встреченную дважды, в правило в собственном списке того лейна, а правило, которое не повторилось за тридцать ревью, убирает. Списки теперь есть, по одному на каждый навык лейна, и у каждого правила написано, на каком лейне его увидели. Из списка реверсера: «Новое чтение кода — это [I]. Для [C] нужен названный второй источник». «Пересчитывать каждое число по бинарнику сохранённой командой, никогда по памяти и никогда по частичному просмотру». «„Никогда“, „только“, „нет X“: говорить, что именно разделяет запуск. Если один случай несёт оба чтения (у Andariel и флаг 0x08, и boss), эта половина остаётся на [I]». А из списка самого архитектора, который он называет своими слепыми пятнами: «Утверждение, решённое на ревью, получает ту же проверку, что и у лейна». «Оценки в плане помечать как оценки».
Бэклог дважды менял форму. 17-го это был один файл в 730 строк и 519 записей, 464 из них вычеркнуты, за два дня в него добавили около 170 записей и «почти каждое вливание лейна конфликтовало в этом файле». ADR-0018 сделал по файлу на запись, без общего оглавления в репозитории, «потому что общее оглавление вернёт ту же горячую точку». Через три дня в папке лежали 55 открытых и 80 закрытых записей, я сказал, что она разрослась, и ADR-0019 перенёс закрытые в архив. На отсечке: 43 открытых, 186 в архиве.
И ночи. 17-го: выключение около 21:38, которое убило сессию на Hell посреди захода. С 18-го на 19-е: девятичасовой сон. 19-го, в воскресенье: к десяти утра три лейна «остановились на лимите использования владельца», то есть на лимите моей подписки, и после этого не легло ничего. 20-го: сбой отладчика под Wine посреди пакета, гонка потоков в gdb 18.1; в 20:12 менеджер памяти убил всех агентов разом, без заметки для продолжения; а с 23:17 до 06:20 машина снова спала, так что журнал записывает 428 из 624 минут одного лейна как сон. Ни одно утверждение от этого не потерялось.
Числа
Где проект сейчас, в сравнении с первым и шестым днём
Спецификации после ревью (28 строк до дня 4, 29 в день 6, 35 в день 8, 36 в день 11)
[C] подтверждённые утверждения в находках
[I] выведенные утверждения в находках
Именованные адреса в Game.exe
Инструменты на Python
Закрытые планы
У каждого показателя своя шкала. Источники: карта исследования, docs/findings, re/symbols.csv, tools/ и docs/plans/done на каждой отсечке.
Подтверждённые и выведенные утверждения в находках
[C] — прочитано в коде и подтверждено чем-то независимым, обычно запуском. [I] — только прочитано в коде. Ночи вырезаны.
- [C] подтверждено
- [I] выведено
Пустые 18-е и 19-е — сон машины и лимит. 20-го обе линии растут вместе, потому что каждое новое чтение ложится как [I], а его запуск поднимает только часть.
Показать числа
| Время | [C] | [I] |
|---|---|---|
| 11 окт. 10:31 | 0 | 0 |
| 11 окт. 13:35 | 7 | 15 |
| 11 окт. 15:05 | 21 | 58 |
| 11 окт. 16:00 | 28 | 59 |
| 11 окт. 16:25 | 42 | 62 |
| 11 окт. 17:57 | 45 | 104 |
| 11 окт. 19:06 | 48 | 148 |
| 11 окт. 20:11 | 48 | 175 |
| 11 окт. 22:12 | 57 | 176 |
| 11 окт. 22:23 | 57 | 176 |
| 12 окт. 08:04 | 80 | 173 |
| 12 окт. 08:41 | 103 | 183 |
| 12 окт. 09:02 | 104 | 184 |
| 12 окт. 09:31 | 108 | 217 |
| 12 окт. 09:58 | 109 | 228 |
| 12 окт. 10:16 | 117 | 278 |
| 12 окт. 10:42 | 135 | 295 |
| 12 окт. 11:51 | 139 | 295 |
| 12 окт. 12:21 | 159 | 291 |
| 12 окт. 13:41 | 161 | 292 |
| 12 окт. 14:10 | 168 | 295 |
| 12 окт. 15:19 | 168 | 320 |
| 12 окт. 15:46 | 184 | 354 |
| 12 окт. 15:58 | 184 | 354 |
| 13 окт. 08:05 | 196 | 348 |
| 13 окт. 08:26 | 204 | 374 |
| 13 окт. 08:33 | 205 | 422 |
| 13 окт. 10:11 | 206 | 448 |
| 13 окт. 13:43 | 223 | 449 |
| 13 окт. 15:59 | 225 | 452 |
| 13 окт. 18:56 | 229 | 453 |
| 13 окт. 19:21 | 236 | 452 |
| 13 окт. 19:28 | 240 | 455 |
| 13 окт. 21:15 | 279 | 429 |
| 13 окт. 22:02 | 279 | 442 |
| 14 окт. 08:11 | 279 | 442 |
| 14 окт. 08:49 | 282 | 443 |
| 14 окт. 09:21 | 282 | 493 |
| 14 окт. 09:36 | 282 | 495 |
| 14 окт. 09:49 | 290 | 536 |
| 14 окт. 10:00 | 291 | 537 |
| 14 окт. 10:09 | 293 | 586 |
| 14 окт. 10:20 | 293 | 587 |
| 14 окт. 11:05 | 332 | 567 |
| 14 окт. 13:10 | 356 | 562 |
| 14 окт. 17:35 | 376 | 560 |
| 14 окт. 19:22 | 376 | 611 |
| 14 окт. 19:56 | 395 | 651 |
| 14 окт. 20:36 | 402 | 691 |
| 14 окт. 20:50 | 446 | 721 |
| 14 окт. 20:59 | 451 | 757 |
| 14 окт. 21:16 | 461 | 796 |
| 14 окт. 22:37 | 506 | 772 |
| 14 окт. 22:50 | 545 | 743 |
| 15 окт. 02:10 | 574 | 733 |
| 15 окт. 02:44 | 587 | 732 |
| 15 окт. 02:54 | 612 | 737 |
| 15 окт. 03:05 | 619 | 727 |
| 15 окт. 03:29 | 629 | 739 |
| 15 окт. 03:57 | 671 | 738 |
| 15 окт. 04:14 | 711 | 716 |
| 15 окт. 07:39 | 718 | 733 |
| 15 окт. 08:47 | 729 | 737 |
| 15 окт. 08:48 | 737 | 779 |
| 15 окт. 08:54 | 746 | 782 |
| 15 окт. 09:05 | 771 | 791 |
| 15 окт. 09:17 | 773 | 848 |
| 15 окт. 19:08 | 774 | 890 |
| 15 окт. 19:10 | 786 | 941 |
| 15 окт. 19:13 | 797 | 940 |
| 15 окт. 19:25 | 801 | 982 |
| 15 окт. 19:33 | 829 | 1015 |
| 15 окт. 19:38 | 829 | 1057 |
| 15 окт. 19:48 | 841 | 1064 |
| 15 окт. 19:56 | 845 | 1066 |
| 15 окт. 20:13 | 845 | 1072 |
| 15 окт. 20:24 | 848 | 1095 |
| 15 окт. 23:42 | 875 | 1092 |
| 15 окт. 23:54 | 886 | 1095 |
| 16 окт. 00:15 | 886 | 1094 |
| 16 окт. 00:21 | 889 | 1096 |
| 16 окт. 01:43 | 905 | 1093 |
| 16 окт. 02:23 | 918 | 1098 |
| 16 окт. 02:28 | 923 | 1103 |
| 16 окт. 03:49 | 956 | 1090 |
| 16 окт. 06:40 | 987 | 1065 |
| 16 окт. 14:29 | 1003 | 1072 |
| 16 окт. 15:31 | 1023 | 1075 |
| 16 окт. 16:08 | 1023 | 1152 |
| 16 окт. 17:21 | 1080 | 1181 |
| 16 окт. 17:36 | 1140 | 1189 |
| 16 окт. 17:53 | 1150 | 1189 |
| 16 окт. 18:24 | 1174 | 1194 |
| 16 окт. 18:34 | 1228 | 1208 |
| 16 окт. 18:35 | 1267 | 1217 |
| 16 окт. 19:26 | 1281 | 1238 |
| 16 окт. 19:29 | 1321 | 1250 |
| 16 окт. 20:49 | 1391 | 1257 |
| 16 окт. 21:01 | 1412 | 1263 |
| 16 окт. 21:29 | 1486 | 1263 |
| 16 окт. 22:07 | 1505 | 1269 |
| 16 окт. 22:19 | 1515 | 1306 |
| 16 окт. 22:26 | 1566 | 1314 |
| 16 окт. 22:41 | 1577 | 1319 |
| 17 окт. 07:51 | 1577 | 1367 |
| 17 окт. 07:56 | 1585 | 1375 |
| 17 окт. 08:02 | 1597 | 1380 |
| 17 окт. 08:35 | 1612 | 1432 |
| 17 окт. 08:47 | 1650 | 1434 |
| 17 окт. 09:04 | 1647 | 1430 |
| 17 окт. 09:09 | 1647 | 1512 |
| 17 окт. 09:45 | 1657 | 1536 |
| 17 окт. 09:55 | 1669 | 1539 |
| 17 окт. 10:44 | 1670 | 1729 |
| 17 окт. 10:50 | 1670 | 1796 |
| 17 окт. 10:58 | 1670 | 1808 |
| 17 окт. 11:07 | 1681 | 1816 |
| 17 окт. 11:15 | 1683 | 1826 |
| 17 окт. 16:44 | 1707 | 1827 |
| 17 окт. 17:18 | 1707 | 1838 |
| 17 окт. 17:33 | 1707 | 1839 |
| 17 окт. 18:26 | 1708 | 1849 |
| 17 окт. 19:16 | 1746 | 1858 |
| 17 окт. 19:27 | 1747 | 1870 |
| 17 окт. 20:06 | 1747 | 1871 |
| 17 окт. 20:56 | 1770 | 1884 |
| 18 окт. 20:09 | 1773 | 1896 |
| 19 окт. 08:00 | 1788 | 1907 |
| 19 окт. 08:10 | 1804 | 1923 |
| 19 окт. 08:44 | 1805 | 1924 |
| 19 окт. 09:26 | 1814 | 1929 |
| 20 окт. 08:30 | 1849 | 1953 |
| 20 окт. 09:11 | 1849 | 1955 |
| 20 окт. 09:54 | 1853 | 2032 |
| 20 окт. 10:17 | 1856 | 2059 |
| 20 окт. 10:29 | 1914 | 2070 |
| 20 окт. 10:51 | 1917 | 2110 |
| 20 окт. 10:58 | 1947 | 2125 |
| 20 окт. 11:19 | 1973 | 2133 |
| 20 окт. 11:51 | 1973 | 2188 |
| 20 окт. 12:29 | 1973 | 2189 |
| 20 окт. 13:11 | 2022 | 2217 |
| 20 окт. 13:20 | 2036 | 2266 |
| 20 окт. 14:53 | 2037 | 2268 |
| 20 окт. 14:53 | 2076 | 2308 |
| 20 окт. 14:56 | 2099 | 2293 |
| 20 окт. 14:57 | 2108 | 2300 |
| 20 окт. 15:43 | 2110 | 2302 |
| 20 окт. 15:47 | 2154 | 2360 |
| 20 окт. 18:55 | 2178 | 2374 |
| 20 окт. 18:55 | 2230 | 2414 |
| 20 окт. 19:19 | 2230 | 2416 |
| 20 окт. 19:54 | 2272 | 2450 |
| 20 окт. 21:31 | 2312 | 2484 |
| 20 окт. 22:21 | 2347 | 2508 |
| 20 окт. 23:11 | 2381 | 2538 |
| 21 окт. 07:17 | 2420 | 2570 |
| 21 окт. 07:37 | 2431 | 2581 |
| 21 окт. 07:46 | 2445 | 2586 |
| 21 окт. 08:21 | 2479 | 2619 |
| 21 окт. 11:24 | 2489 | 2628 |
| 21 окт. 11:53 | 2539 | 2667 |
| 21 окт. 11:57 | 2540 | 2667 |
В шестой день в находках было 1 150 подтверждённых утверждений против 1 189 выведенных. Теперь 2 540 против 2 667, и доля та же, 49 процентов, потому что каждое чтение новой области приходит выведенным, а запуск подтверждает часть. Спецификации, которые и есть результат, прошли от 2 546 подтверждённых и 1 539 выведенных к 3 791 и 2 322. Именованных адресов в Game.exe стало 3 373 вместо 1 814, инструментов 170 вместо 91, рецептов сохранений 233 вместо 112, закрытых планов 44 вместо 36. Вики, про которую в шестой день я написал, что она хорошая и её нужно дорабатывать, получила страницы про бой, характеристики и состояния, квесты и экономику.
Что открыто
- Запуск по навыкам. Фаза плана 0045 на харнессе ждёт оба слота: пять опровергнутых утверждений о снарядах, Blaze, навык, который ни один запуск не применял, и обработчик того Fleshripper. Три строки навыков появятся на карте, когда она начнётся.
- Последние четыре пакета каталога: предметы с Unsummon, потом ещё три.
- От сида к миру, запуск 2: отметки пересозданных монстров в логе и в модели, перепроверить два расхождения, около шестнадцати сессий.
- Оставшиеся пакеты ревизии, двенадцать, и 414 заблокированных утверждений, десяти из которых нужен я.
- Фазы четыре и пять, анимация и тайминг кадров, потом ИИ монстров: плана пока нет; решение о конвейере фаз позволяет плану четвёртой фазы пойти следом за запуском по навыкам.
- То, что сыграть могу только я, всё помечено как необязательное: кузница, Andariel и Ancients со вторым игроком, шаги с боссами в квестах, пара сессий с Diablo из пакета по квестовым дропам и сессия у Hellforge на Hell ради одного свойства treasure class, где пилот «погиб на 19-м переходе в River of Flame».
Воксельный движок прожил свои пять дней в другом репозитории и прошёл от версии 0.3 до 0.24.