Все страницы форматов ↓
Юниты, скрипты, конфигурации

ИИ — профили компьютерного противника

Источник: coreprime/kbot @ 0ab97bf · Редактировать на GitHub

Файлы ai/*.txt — это текстовые профили компьютерного противника. Каждый профиль задаёт приоритеты строительства и лимиты юнитов для каждого уровня сложности; движок читает их, когда на карте настроен игрок под управлением ИИ. Ключ aiprofile= в OTA выбирает, с каким профилем начинается конкретная карта, но в лобби игрок может его переопределить.

Tip

Попробуйте сами.

# Plain-text — just read them
ls $(kbot ctx path)/ai/
head -40 $(kbot ctx path)/ai/default.txt

В kbot. Обозреватель ресурсов студии показывает профиль на вкладке AI Profile, а kbot mount выводит его командой describe ai/<name>.txt (см. Что показывает kbot).

Из Go. Используйте formats/ai из kbot-io:

import "github.com/coreprime/kbot-io/formats/ai"

raw, _ := os.ReadFile("ai/default.txt")
profile, _ := ai.Parse(raw)
// profile.Preamble: lines before the first plan; profile.Plans: plan.Name,
// plan.Weights, plan.Limits; profile.Diagnostics: lines read unusually.
settings := ai.NewResolver(units).Apply(profile, ai.Easy) // per-unit result

Кратко

Профиль — это последовательность планов, по одному на уровень сложности. Каждый план содержит директивы Weight и Limit, цель которых — одно имя юнита (ARMCOM), слово категории (PLANT, LEVEL3, SPECIAL) или ALL.

plan easy

Weight ARM      0.2
Weight CORE     0.2
Weight PLANT    2
Weight CONSTR   3
Weight ARMACK   2
Weight CORACK   2

Limit  ARMSILO  1
Limit  CORSILO  1


plan medium

Weight ARM      1.0
Weight CORE     1.0
...

Директивы

Директива Синтаксис Смысл
plan <word>… plan easy Начинает новый блок плана. Следующие за ним строки Weight/Limit действуют, только если план соответствует сложности игры, — до следующего plan.
Weight <target> <value> Weight ARMCK 0.5 Умножает приоритет строительства цели (см. как сочетаются веса).
Limit <target> <value> Limit ARMSILO 1 Ограничивает, сколько юнитов цели может быть у компьютерного игрока: -1 — без ограничений, 0 или любое другое отрицательное значение — запрет.

Как TA 3.1c читает текст (так же поступает formats/ai из kbot-io):

  • Строка делится на слова по любым пробельным символам — пробелам, табуляциям, CR, VT, FF, — а # заканчивает строку в любом месте, даже внутри слова.
  • Первое слово — директива, сравнивается без учёта регистра. Строка, первое слово которой — что-то другое, игнорируется; именно так пропускаются строки // comment в оригинальных файлах. Слова после значения тоже игнорируются, так что // note в конце строки ничему не мешает.
  • Значение — это числовое начало третьего слова. Вес — десятичное число (0.5, .5, 2, 1e1); лимит — целое, которое переполняется по модулю 32 бит. Слово значения, которое не является числом, читается как 0, и директива всё равно применяется: Limit CORFORT O (буква O) в оригинальном krogoth.txt запрещает CORFORT, а Limit ARM DECOM 4 ограничивает всю категорию ARM нулём.
  • Строки до первой строки plan при запуске игры игнорируются, потому что ни один план ещё не подошёл. Они могут подействовать, если профиль перезагружается во время игры. Оригинальный krogoth.txt начинается с двух таких строк (weight cormakr 0.2, weight armmakr 0.2). Файлы ИИ TA: Kingdoms вообще не используют plan — см. ниже TA: Kingdoms — профили без plan.

Уровни сложности

Стандартные профили поставляются с тремя планами: easy, medium и hard. План действует на уровне сложности, если одно из его слов (без учёта регистра) называет этот уровень — plan medium hard покрывает оба, — или если его первое слово any. План, слова которого не называют ни одного уровня (plan brutal, голый plan), не подходит ни к чему: строки под ним игнорируются до следующей строки plan.


Имена юнитов и слова категорий

И Weight, и Limit могут быть нацелены на:

  • UnitName юнита — например, ARMCOM, CORRAID (сравнение без учёта регистра). Директива действует только на этот юнит и закрепляет его: последующие строки Weight (для веса) или Limit (для лимита) его больше не меняют.
  • Слово категории — ARM, CORE, PLANT, CONSTR, LEVEL3, SPECIAL, … — сопоставляется со словами поля Category= каждого юнита. Действует на каждый подходящий незакреплённый юнит.
  • ALL — каждый незакреплённый юнит.

Каждый юнит начинает со 100 % приоритета и без лимита. Вес умножает текущий процент, отбрасывает дробную часть и ограничивает результат диапазоном 0–100 %, поэтому вес больше 1 может вернуть юнит, пониженный раньше, но никогда не поднимет его выше 100 %. Лимит заменяет текущий. В плане easy из default.txt строка Weight ARM 0.2 оставляет каждому юниту ARM 20 %; следующая Weight ARMRAD 0.25 снижает радарную вышку ARM до 5 % и закрепляет её; Weight PLANT 2 возвращает каждый завод ARM с 20 % на 40 %.

Important

Псевдонимы категорий сопоставляются со списком токенов Category= юнита, а не с каким-либо файлом классификации. Псевдоним категории «существует», только если его объявляет хотя бы один юнит. Ошибитесь в написании LEVL3 — и директива молча ничего не сделает (просмотрщики kbot помечают её как не подходит ни одному юниту).


Разбор примера — фрагмент default.txt

// DEFAULT PROFILE

//--------------------------- EASY

plan easy

Weight ARM 0.2          // Every Arm unit to 20%
Weight CORE 0.2

Weight ARMRAD 0.25      // Radar towers to 5%, locked
Weight CORRAD 0.25

Weight ARMMAKR .1       // …metal makers to 2%, locked
Weight CORMAKR .1

Weight PLANT 2          // Factories back up to 40%
Weight CONSTR 3         // Constructors to 60%

// encourages advanced units
Weight ARMACK 2         // Advanced Construction Kbots
Weight CORACK 2
Weight ARMACV 2
Weight CORACV 2
Weight ARMACA 2
Weight CORACA 2
Weight SPECIAL 2
Weight LEVEL3 2

Как это читать: на лёгкой сложности приоритет каждого юнита ARM и CORE падает до 20 %; радарные вышки опускаются до 5 %, а синтезаторы металла — до 2 % (и те и другие затем закреплены); заводы (PLANT) и строители (CONSTR) поднимаются обратно до 40 % и 60 %, а собственные строки улучшенных строителей удваивают их 60 % до потолка в 100 % и закрепляют их.


Профили для отдельных карт

Cavedog поставляет несколько профилей, настроенных под типы карт:

Профиль Где используется
default.txt Большинство обычных карт
metal.txt Карты, богатые металлом (Metal Heck и подобные)
airbattle.txt Карты с упором на авиацию
seabattle.txt Карты с упором на флот
hover.txt Карты для ховеркрафтов
acid.txt Карты кислотного мира
urban.txt Городские карты
waterwrld.txt Карты водного мира
krogoth.txt Миссия с боссом-Кроготом
missions.txt Миссии кампании

Нужный профиль выбирает .ota карты через aiprofile=, например aiprofile=metal.


TA: Kingdoms — профили без plan

Note

Этот раздел описывает только отличия TA:K. TAK использует то же соглашение об именах файлов ai/*.txt и тот же синтаксис директив weight/limit, но считает директиву plan необязательной.

Все оригинальные профили ИИ TA: Kingdoms (ai/default.txt, набор ai/mission*.txt кампании) перечисляют директивы weight/limit вообще без строк plan — на файл приходится один неявный уровень сложности. Структура такая: длинный блок весов, за ним длинный блок лимитов, сгруппированные по сторонам через префикс имени юнита.

Разбор примера — первые 30 строк ai/default.txt

// Kingdoms Default AI Profile 3-28-99


weight araarch 5
weight araat 1
weight arabow 8
weight arabroad 5
weight arabuild 10
weight aracan 4
weight aracastl 10
weight araclay 5
weight aradrag 25      // Dragons: top priority
weight arafast 1
weight arakeep 10
weight araknigh 5
weight aralode 10
weight aramana 5
weight arangate 0      // 0 = never build
weight arapal 8
weight arapries 10
weight arapult 1
weight arasmith 8
weight araspy 4
weight arassh 1
weight arasword 5
weight aratre 1
weight arawall 0
weight arawar 1

Если просмотреть, куда в default.txt смещены веса, видны приоритеты Cavedog:

  • aradrag 25 — дракон Aramon намеренно перевешен: ИИ строит драконов охотнее, чем что-либо другое.
  • arabuild 10, aracastl 10, arakeep 10, arapries 10 — у всех экономических и строительных типов вес 10.
  • arawall 0, arangate 0 — явный ноль, никогда не строятся.
  • araat 1, arafast 1, arassh 1 — базовые юниты, которые ИИ отодвигает в пользу альтернатив более высокого уровня.

Та же картина повторяется для юнитов tar*, ver* и zon* дальше в файле.

Блок лимитов

Под блоком весов идёт параллельный блок лимитов:

limit araarch 16
limit araat 8
limit arabow 16
limit arabroad 16
limit arabuild 10
limit aracan 3
limit aracastl 2       // Only 2 castles per game
limit araclay 3
limit aradrag 1        // ONE dragon, even though weight=25
limit arafast 4
limit arakeep 2
limit araknigh 16
…

Обратите внимание на асимметрию: у aradrag вес 25 (высокий приоритет), но лимит 1 (не больше одного). Так ИИ TA:K строит героя: высокий вес заставляет построить его рано, а низкий лимит держит состав армии в разумных рамках.

Статистика профилей

default.txt и файлы миссий кампании устроены одинаково:

Профиль Строк weight Строк limit Планов
ai/default.txt 104 104 0
ai/mission06.txt 104 104 0
ai/mission08.txt (миссия Iron Plague) 161 162 0

В файлах миссий Iron Plague таблицы весов и лимитов богаче, потому что они охватывают юниты Creon (префикс CRE), которых нет в default.txt основной игры.

Как kbot обрабатывает файлы без plan

ai.Parse из kbot-io помещает все строки до первой строки plan в AIFile.Preamble — так же с ними поступает TA (см. выше); для профиля TA: Kingdoms ai.ParseWith(data, ai.ParseOptions{DefaultPlan: true}) читает их в один неявный план, который подходит к любой сложности. Просмотрщики kbot показывают эти строки на отдельной вкладке Before first plan и сообщают обе вещи: TA игнорирует их при запуске игры, а профили TA: Kingdoms, в которых нет строк plan, применяют их на любой сложности. Как TA: Kingdoms применяет веса больше 1, kbot не моделирует.

ai.IsAIFile() смотрит на первое слово каждой строки: файл считается профилем, если какая-нибудь строка начинается с директивы, записанной обычным образом (строка plan, называющая easy, medium, hard или any, либо строка weight/limit, значение которой начинается с числа). Так распознаются профили TAK, в которых нет plan, и профили с разделением табуляциями, а .txt, где «weight» или «limit» просто упоминаются в тексте, за профиль не принимается.


Подводные камни

Warning

Игра ни о чём не сообщает. Имя юнита с опечаткой читается как категория, которая не подходит ни одному юниту, и ничего не делает; значение, не являющееся числом, читается как 0 (так что лимит запрещает цель); строки до первого plan при запуске игры игнорируются. Первый признак сломанного профиля обычно звучит как «ИИ ведёт себя странно». Просмотрщики kbot отмечают каждый из этих случаев (см. ниже).

  • Limit 0 или любой отрицательный лимит, кроме -1, запрещает ИИ строить эту цель. -1 снимает ограничение.
  • # заканчивает строку где угодно, даже внутри слова; блочных комментариев нет. // работает лишь потому, что строка, первое слово которой не директива, игнорируется, а слова после значения тоже игнорируются.
  • Вес больше 1 никогда не поднимает юнит выше 100 %. Он может только вернуть юнит, который раньше понизил вес категории.
  • Первая строка, называющая юнит, закрепляет его. Ставьте строки для конкретных юнитов после строк категорий, которые они должны уточнять.
  • Пробельные символы между токенами значимы только как разделители — табуляции, пробелы и несколько пробелов подряд работают одинаково.
  • Вложенных или общих секций нет. Каждый блок plan должен заново объявить все нужные ему веса и лимиты.

Что показывает kbot

Обозреватель ресурсов студии (вкладка AI Profile) и describe в kbot mount читают профиль так же, как игра:

  • Before first plan — строки преамбулы с пометкой, что при запуске игры они игнорируются.
  • По вкладке на каждый план, где каждая цель помечена как unit, category или all units по units/*.fbi установки (имя и Category=). Категория, которой нет ни у одного юнита, — а именно так читается имя юнита с опечаткой, — помечается как matches no unit. Веса показаны как множители с полосой процента, который остаётся у юнита со 100 %; лимиты — как ∞ Unlimited, Disabled (0 или любое отрицательное значение, кроме -1) или Max: N.
  • Строки, которые игра читает иначе, — диагностика kbot-io, например слово значения, которое не является числом (O читается как 0), или слова после значения. Если слово значения отличается от числа, которое читает игра, оно показано рядом (written "O"); другая запись того же числа, например .1 или 0.10, не показывается.
  • At game start (в студии; kbot mount выводит количества) — для easy, medium и hard каждый юнит, вес или лимит которого меняет профиль, с 🔒 у значений, закреплённых строкой юнита.

Типичные размеры

Показатель Диапазон в профилях Cavedog
Размер файла 1–4 КБ
Планов в файле 3 (easy/medium/hard)
Директив weight в плане 20–80
Директив limit в плане 0–10

См. также

  • TDF — метаданные карты .ota, которые выбирают профиль ИИ.
  • Глоссарий — side (сторона), category (категория).