# WishAudit — журнал изменений

Модуль «Дележ добычи» (рандомайзер). Исходная версия аддона — 0.9.0.

---

## 1.1.1

**Шрифты: проба перестала браковать годное**

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

* Презумпция перевёрнута: шрифт считается годным по умолчанию, проба лишь
  подтверждает или уличает.
* Три исхода вместо двух: «годен», «негоден» и **«не смог измерить»** —
  последнее больше не приговор, а повод попробовать позже.
* Проба живёт на видимом месте, работает после готовности интерфейса и
  повторяется до шести раз с нарастающим промежутком.
* Надписи переодеваются задним числом: когда шрифт подхватился, он
  переприменяется ко всему уже построенному. Реестр на слабых ссылках —
  утечки нет.
* Жалоба в чат только при подтверждённой негодности.

**Стенд в поставке**

Папка `Tests` с проверками и запиской. В `.toc` не значится, игра его не
грузит. Записано, почему нельзя трогать прогрев генератора.

---

## 1.1.0 — колесо стало читаемым

* **Спицы.** Пятая текстура — клин в 0.7°, тёмный, ложится на каждую границу
  секторов поверх заливки. Два одноклассника подряд больше не читаются как
  один сектор с неровной заливкой.
* **Номера.** Цифра в секторе (если он шире 9°) и та же цифра в легенде.
  Цвет цифры выбирается по яркости заливки.
* **Цвета — по надобности, а не через один.** Каждый сектор сверяется с
  соседом; близкие оттенки разводятся. Попутно закрыт **разрыв на стыке
  кольца**: круг замкнут, и прежнее чередование по чётности ломалось при
  нечётном числе участников — последний сектор соседствовал с первым той же
  яркости.
* **Легенда в две колонки.** Кто начинается в первых 180° по часовой (правая
  половина круга) — справа, остальные слева. Ники режутся до 11 знаков,
  ширина колонки посчитана под этот предел.
* Окно колеса выросло до 470 в высоту.

---

## 1.0.1 (вторая сборка) — вкладка настроек и вторая забава

Версия по указанию оставлена прежней, **хотя протокол менялся**. См. раздел
«Долги» ниже.

**Вкладка «Roll» в настройках**

Вставляется в готовую таблицу через реестр AceConfig, без правки
`Options.lua`.

* «Всегда»: показывать анимацию / показывать окно победителя.
* «Когда меня нет среди претендентов»: то же отдельно для чужих разролов.
* Прочее: звук, зерно из серверного `/roll`, объявление в чат, отладка,
  кнопка «Забыть закрытые роллы».

**Крестик**

Закрывает ролл до конца сессии: ни анимация, ни окно победителя больше не
появятся, итог придёт объявлением в чат. Тот, кто выключил анимацию, узнаёт
исход **позже** зрителей на 1.6 секунды, а не раньше.

**Колесо фортуны**

* Переключатель забав в окне РЛа.
* Сбор бросков: слушается системный чат, берётся **первый** `/roll` (1-100)
  от каждого, посторонние вне группы не считаются, порядок бросков —
  порядок секторов. Чат слушает **только РЛ**; рейдеры получают готовый
  список одним пакетом.
* Круг режется на 360 целых градусов методом наибольших остатков.
  Победитель выбирается **по нарисованным градусам**, а не по сырым
  броскам, — стрелка всегда встаёт там, где глаз видит сектор. Плата:
  округление доли не более чем на 0.14%.
* Крутится стрелка, а не круг: повернуть фрейм в WoW нельзя, а вращать
  сотни текстур каждый кадр — расточительство. Имена в легенде при этом
  читаемы всё время вращения.
* Секторов в игре нет — изготовлены четыре TGA (1°, 5°, 15°, 45°), из
  которых складывается любой сектор. Первый набор дал тёмные швы по стыкам,
  нахлёст расширен.

---

## 1.0.1 (первая сборка) — «у рейдеров пустые ячейки»

* Пакет **проверен настоящим сериализатором RC**: имена, кириллица и ссылка
  на предмет доходят целыми. Догадка про порядковые номера отвергнута —
  экономия 20 байт из 363, а в пятёрке индексы у каждого свои, и шмотка ушла
  бы не тому.
* Имена всё же переведены на **плоскую строку** вместо вложенной таблицы:
  короче и снимает целый класс возможных бед.
* **Номер протокола поднят до 2** — старый клиент теперь говорит «другой
  версии протокола» вместо молчаливого кручения пустоты.
* Первая версия проверки шрифтов (переделана в 1.1.1).
* Объявление в чат приведено к виду `[Ссылка], победил Ник`.
* Команда `/wish roll debug` — печатать содержимое приходящих пакетов.

---

## 0.11.0 — лента стала колесом

Имена тасуются один раз (Фишер-Йетс) и идут по кругу этим же порядком до
конца ленты: `3 2 5 1 4 · 3 2 5 1 4 · ...` Каждое имя встречается ровно
одинаковое число раз.

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

Побочно: путь барабана теперь одинаков при любом числе претендентов.

---

## 0.10.1 — имена перестали вылезать

* Размер подбирается по **фактической ширине строки**. Прежняя формула
  считала по числу букв и не знала, что разрядка вставляет пробел между
  каждой парой символов: «Морруталь» из девяти знаков становилась
  семнадцатью.
* Жёсткий заслон: строка физически не может выйти за табличку.
* Имя победителя в финале ужимается под ширину окна.
* **Классовые цвета** на табличках; на победной подмешан белый — иначе
  тёмные классы тонули в латунной подсветке.

---

## 0.10.0 — первая сборка модуля

Четыре новых файла, правок в существующем коде — одна строка (версия) плюс
строки в `.toc`.

* **Протокол.** Один пакет на весь ролл: предмет, имена, зерно, момент
  старта. Победитель **не передаётся** — каждый клиент выводит его из зерна
  детерминированным генератором (Парк-Миллер, целочисленное состояние,
  результат побитово одинаков на любой машине).
* **Синхронизация.** Момент старта задан по **серверным часам**: клиент
  ловит смену секунды `GetServerTime()` и привязывает её к точному
  `GetTime()`. Положение барабана — чистая функция от «сейчас минус старт»,
  поэтому опоздавший пакет не сдвигает финал, а клиент догоняет анимацию.
* **Проверяемость.** Зерно по умолчанию из серверного `/roll 1-1000000` —
  бросок виден всем в чате, любой может пересчитать исход.
* Кнопка «Рандомайзер» в окне голосования RC и команда `/wish roll`.
* Окно РЛа: предмет из текущей сессии, список группы, «Из голосования».
* Шрифты Forum и JetBrains Mono в поставке, с лицензиями OFL.
* Отказоустойчивость: `/roll` молчит — локальное зерно; часы разошлись —
  не верим им; шрифт не читается — игровой.

---

# Ошибки, найденные стендом по ходу работы

Ни одну из них не удалось заметить глазами при написании.

| Что | Чем грозило |
|---|---|
| Генератор без прогрева | Перекос жребия: при четырёх претендентах последний получал 23.3% вместо 25%, на последовательных зёрнах — 21.3% |
| Клык и затемнение под лентой | Дочерний фрейм рисуется поверх текстур родителя — указатель оказался бы под табличками |
| Разрядка не учтена в подборе размера | Имена вылезали за края и наезжали друг на друга |
| Смена формата пакета | Запуск падал **у самого РЛ**: пакет уже нёс строку, а его собственный код искал таблицу |
| Чередование цветов по чётности | Разрыв на стыке кольца при нечётном числе участников |
| Проба шрифтов | Браковала годный шрифт у части рейда |
| Дубликат ключа в самом стенде | Три проверки шрифтов врали, подтверждая что угодно |

---

# Долги

**Не проверено в игре.** Всё, что касается отрисовки: повороты текстур,
градиенты, обрезка по краю, загрузка TGA. Стенд ловит логику, но не
рисование. Знак поворота у клиньев не проверен — колесо может собраться
зеркально (лечится одним знаком минус).

**Не сделано, обсуждалось:**

* Дозагрузка иконки предмета в окне ролла и колеса — у не видевших вещь она
  остаётся знаком вопроса до второго ролла. `ContinueOnItemLoad` есть только
  в окне РЛа.
* Строка состояния переписывается каждый кадр одним и тем же текстом.
* Функция настроек пробегает по умолчаниям при каждом обращении, а зовётся
  из звука до 15 раз в секунду.
* Обёртки `pcall` вокруг `RollUI:Run` и `RollWheel:Run` — они вызываются
  прямо из обработчика сетевого пакета.
* Прослойка над связью: сейчас шесть зацепок за внутренности RC.
* Восемьдесят табличек барабана остаются в запасе навсегда.
* Переполнение легенды колеса, если больше 13 секторов начнутся в одной
  половине.
* Всё намертво по-русски.

**Принято сознательно:**

* Версия 1.0.1 выпущена дважды с разным протоколом — по указанию. Правило
  железное: меняется протокол, меняется версия, иначе проверка версий врёт.
* Сверка часов раз в 10 минут оставлена как есть: попасть ею в разгон
  барабана — меньше трёх сотых вероятности, и цена промаху лишь дёрнувшаяся
  лента, победитель и время вскрытия не меняются.
* Заранее вычислить исход может тот, кто читает переменные аддона: зерно
  приходит за 15 секунд до вскрытия, а при серверном `/roll` вообще
  публично. Это оборотная сторона проверяемости.

---

# Отдельно: браузерный стенд

`roll-sandbox.html` — обе забавы вне игры. Ползунок 1-20, имена и роллы
кидает сам.

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