# Квитанции и коды причин

> Квитанция каждой команды содержит код статуса и код причины. На них опирается самокоррекция ботов и агентов: «почему не получилось» превращается в машиночитаемое число.

Источник: https://war3ai.com/ru/docs/reason-codes/

```python
r = g.train(barracks, "hfoo")
bool(r)        # False
r.status       # 1              -> rejected
r.verdict      # 3              -> не хватает пищи
r.reason       # 'rejected（人口不够）'   (= «не хватает пищи»)
r.exec_us      # сколько микросекунд команда выполнялась в игровом потоке
```

`if r:` эквивалентно `r.status == 0` (движок принял команду).

## Код статуса `status`

| Код | Имя | Значение | Типичная причина |
|---|---|---|---|
| 0 | `accepted` | Движок принял команду | — (но «принята» ≠ «выполнена», см. ниже) |
| 1 | `rejected` | Движок отклонил команду | Смотрите `verdict` |
| 2 | `bad_unit` | Юнита нет или дескриптор не совпадает | Юнит уже погиб; использован устаревший объект юнита |
| 3 | `not_owner` | Это не ваш юнит | Командуете чужим юнитом от имени `player` |
| 4 | `fault` | Исключение при выполнении (рантайм его перехватил, игра не упадёт) | Сообщите нам, приложив шаги воспроизведения |
| 5 | `bad_args` | Неверные аргументы | Ошибка в координатах, номере ячейки или четырёхсимвольном коде |
| 6 | `unsupported` | Не поддерживается | В этой версии рантайма нет такой возможности |
| 7 | `bad_target` | Недопустимая цель | Цели уже нет; неподходящий тип цели |
| 8 | `forbidden` | Роль полосы этого не позволяет | Приказ от имени `observer` |
| 97 | `cancelled` | В блоке пачки возникло исключение, вся пачка не отправлена | Ошибка в коде внутри блока `with g.batch():` |
| 98 | `held` | Юнита удерживает слой с более высоким приоритетом, команда не отправлена | Этого юнита держит рефлекторный слой эталонного мозга или ручной приказ из консоли |
| 99 | `timeout` | Тайм-аут | Игра на паузе или подвисла, и дедлайн истёк (просроченные команды уже не выполняются) |

## Код причины `verdict`

При отклонении рантайм объясняет причину с помощью собственной проверки выполнимости движка. Можно и не отдавать приказ, а сначала спросить: `g.can_do(юнит, код)` возвращает те же коды.

| Код | Значение | Что делать |
|---|---|---|
| 0 / 220 | Можно | — |
| 3 | Не хватает пищи | Постройте здание для пищи; `g.production(b).blocked` покажет проблему заранее |
| 8 | Не хватает золота | Подождите; перед приказом проверяйте `g.can_afford(code)` |
| 9 | Не хватает древесины | Отправьте больше рабочих на лес |
| 32 | Очередь тренировки заполнена (7 мест) | Держите в очереди 1 юнит: ставьте следующего, когда `g.queue(b)` опустеет |
| 183 | Нет требуемой технологии / здания | Сначала постройте требуемое здание или перейдите на следующий тир |
| 185 | Здание занято | Алтарь воскрешает героя; главное здание нельзя улучшить, пока его очередь не пуста |
| 221 | Такого пункта нет / строится / улучшается / уже существует | Герой уже есть (погибшего нужно `revive`); этот магазин такое не продаёт |
| 89 | Товар ещё не поступил в магазин | В начале матча товары появляются по времени из таблицы предметов; у только что построенного магазина отсчёт идёт с момента завершения постройки |
| 1001 | Цель не видна | Цель в тумане войны или под чёрной маской; сделайте `attack_move` в её позицию |

## «Принята» ≠ «выполнена»

Квитанция лишь сообщает, что «движок принял команду», и считывается в том же кадре. Что произойдёт потом, она не отражает:

| Команда | Что может сорваться уже после принятия | Как проверить |
|---|---|---|
| Строительство | Точку в лесу движок тоже сразу принимает, а срывается всё, когда рабочий дойдёт до места | Используйте `build_near` (он следит, появился ли фундамент) или ждите `production.done` |
| Применение способности | Прервали, не хватило маны | На следующем тике проверьте, ушла ли способность на перезарядку: `g.cooldown(u, способность)` |
| Тренировка | Встала в очередь, но пищи не хватает, и она не начинается | `g.production(b).blocked` |
| Движение / атака | Перебита другой логикой (или слоем с более высоким приоритетом) | `g.current_target(u)`, `g.order_of(u)` |

## Методы-запросы

Эти методы не отдают приказов, а только спрашивают движок; результат тоже кладётся в поле `value` квитанции (SDK возвращает само значение):

| Метод | Возвращает |
|---|---|
| `g.can_do(u, code)` / `g.can_do_many([(u, code), ...])` | Код причины из таблицы выше |
| `g.tech(code, player=None)` / `g.tech_many([...])` | Уровень исследования / число построенных зданий (с учётом цепочки улучшений) |
| `g.visible(x, y)` | Видна ли эта точка нашей стороне |
| `g.gold_left(mine)` | Сколько золота осталось в руднике |
| `g.enemy_ai_plan(вражеский_юнит)` | Куда капитан компьютерного противника поведёт армию (работает только для компьютерного ИИ) |
