Todas as páginas de formatos ↓
Unidades, scripts e ficheiros de configuração

IA — perfis dos adversários do computador

Fonte: coreprime/kbot @ 0ab97bf · Editar no GitHub

Os ficheiros ai/*.txt são perfis dos adversários do computador, em texto simples. Cada perfil declara, por nível de dificuldade, as prioridades de construção e os limites de unidades; o motor lê-os quando um jogador de IA é configurado para um mapa. A chave aiprofile= do OTA escolhe o perfil com que um mapa começa, mas o utilizador pode substituí-lo no lobby.

Tip

Experimente por si.

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

No kbot. O explorador de recursos do estúdio mostra um perfil no separador AI Profile, e o kbot mount imprime-o com describe ai/<name>.txt (ver O que o kbot mostra).

A partir de Go. Use o formats/ai do 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

Visão geral

Um perfil é uma sequência de planos, um por nível de dificuldade. Cada plano contém diretivas Weight e Limit cujo alvo é um único nome de unidade (ARMCOM), uma palavra de categoria (PLANT, LEVEL3, SPECIAL) ou 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
...

Diretivas

Diretiva Sintaxe Significado
plan <word>… plan easy Começa um novo bloco de plano. As linhas Weight/Limit que se seguem só se aplicam quando o plano corresponde à dificuldade do jogo, até ao plan seguinte.
Weight <target> <value> Weight ARMCK 0.5 Multiplica a prioridade de construção do alvo (ver como os pesos se combinam).
Limit <target> <value> Limit ARMSILO 1 Limita o número de unidades do alvo que um jogador do computador pode ter: -1 é ilimitado, 0 ou qualquer outro valor negativo proíbe-o.

Como o TA 3.1c lê o texto (o formats/ai do kbot-io faz o mesmo):

  • Uma linha é dividida em palavras em qualquer espaço em branco — espaços, tabulações, CR, VT, FF — e # termina a linha onde quer que apareça, mesmo dentro de uma palavra.
  • A primeira palavra é a diretiva, comparada sem distinguir maiúsculas de minúsculas. Uma linha cuja primeira palavra seja outra coisa é ignorada; é assim que as linhas // comment dos ficheiros comerciais são saltadas. As palavras depois do valor também são ignoradas, por isso um // note no fim da linha não faz mal.
  • Um valor é o prefixo numérico da terceira palavra. Um peso é um número decimal (0.5, .5, 2, 1e1); um limite é um inteiro que dá a volta em 32 bits. Uma palavra de valor que não seja um número lê-se como 0 e a diretiva aplica-se na mesma: o Limit CORFORT O (a letra O) do krogoth.txt comercial proíbe o CORFORT, e Limit ARM DECOM 4 limita toda a categoria ARM a 0.
  • As linhas antes da primeira linha plan são ignoradas quando uma partida começa, porque ainda nenhum plano correspondeu. Podem aplicar-se se o perfil for recarregado durante uma partida. O krogoth.txt comercial começa com duas linhas destas (weight cormakr 0.2, weight armmakr 0.2). Os ficheiros de IA do TA: Kingdoms não usam plan de todo; veja TA: Kingdoms — perfis sem plan mais abaixo.

Níveis de dificuldade

Os perfis originais trazem três planos chamados easy, medium e hard. Um plano aplica-se a uma dificuldade quando uma das suas palavras (sem distinguir maiúsculas de minúsculas) nomeia essa dificuldade (plan medium hard cobre as duas) ou quando a sua primeira palavra é any. Um plano cujas palavras não nomeiam nenhuma dificuldade (plan brutal, um plan sozinho) não corresponde a nada: as linhas abaixo dele são ignoradas até à linha plan seguinte.


Nomes de unidades e palavras de categoria

Tanto Weight como Limit podem ter como alvo:

  • O UnitName de uma unidade, por exemplo ARMCOM, CORRAID (comparado sem distinguir maiúsculas de minúsculas). A diretiva aplica-se só a essa unidade e bloqueia-a: as linhas Weight seguintes (no caso de um peso) ou as linhas Limit seguintes (no caso de um limite) já não a alteram.
  • Uma palavra de categoria — ARM, CORE, PLANT, CONSTR, LEVEL3, SPECIAL, … — comparada com as palavras do campo Category= de cada unidade. Aplica-se a todas as unidades correspondentes que não estejam bloqueadas.
  • ALL: todas as unidades que não estejam bloqueadas.

Todas as unidades começam com 100 % de prioridade e sem limite. Um peso multiplica a percentagem atual, trunca-a para um número inteiro e restringe-a ao intervalo 0–100 %, por isso um peso acima de 1 pode repor uma unidade reduzida antes, mas nunca a leva além de 100 %. Um limite substitui o atual. No plano easy do default.txt, Weight ARM 0.2 deixa todas as unidades ARM a 20 %; o Weight ARMRAD 0.25 que vem depois leva a torre de radar ARM a 5 % e bloqueia-a; Weight PLANT 2 traz cada fábrica ARM de volta de 20 % para 40 %.

Important

Os aliases de categoria são comparados com a lista de tokens do Category= da unidade, e não com um ficheiro de taxonomia. Um alias de categoria só "existe" se pelo menos uma unidade o declarar. Basta escrever LEVL3 por engano para a diretiva não fazer nada, sem qualquer aviso (os visualizadores do kbot marcam-na como matches no unit).


Exemplo comentado — fragmento do 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

Como ler isto: na dificuldade easy, todas as unidades ARM e CORE descem para 20 % de prioridade; as torres de radar descem para 5 % e os conversores de metal para 2 % (ficando ambos bloqueados); as fábricas (PLANT) e os construtores (CONSTR) voltam a subir para 40 % e 60 %, e as linhas próprias dos construtores avançados duplicam os seus 60 % até ao teto de 100 % e bloqueiam-nos.


Perfis específicos de mapas

A Cavedog inclui alguns perfis ajustados a determinados mapas:

Perfil Usado por
default.txt A maioria dos mapas genéricos
metal.txt Mapas ricos em metal (o Metal Heck e afins)
airbattle.txt Mapas centrados no combate aéreo
seabattle.txt Mapas centrados no combate naval
hover.txt Mapas com muitos hovercrafts
acid.txt Mapas do mundo ácido
urban.txt Mapas urbanos
waterwrld.txt Mapas do mundo aquático
krogoth.txt A missão do Krogoth, o chefe final
missions.txt Missões da campanha

O .ota do mapa escolhe qual através de aiprofile=, por exemplo aiprofile=metal.


TA: Kingdoms — perfis sem plan

Note

Esta secção trata só do que muda no TA:K. O TAK usa a mesma convenção de nomes ai/*.txt e a mesma sintaxe das diretivas weight/limit, mas trata a diretiva plan como opcional.

Todos os perfis de IA do TA: Kingdoms comercial (ai/default.txt, o conjunto ai/mission*.txt da campanha) listam diretivas weight/limit sem nenhuma linha plan: há apenas uma dificuldade implícita por ficheiro. A estrutura é um longo bloco de pesos seguido de um longo bloco de limites, agrupados por lado segundo o prefixo do nome da unidade.

Exemplo comentado — as primeiras 30 linhas do 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

Um levantamento do peso dado a cada unidade no default.txt revela as prioridades da Cavedog:

  • aradrag 25 — o Dragão de Aramon tem um peso propositadamente exagerado; a IA constrói dragões com mais vontade do que qualquer outra coisa.
  • arabuild 10, aracastl 10, arakeep 10, arapries 10 — todos os tipos de economia/construtor ficam com peso 10.
  • arawall 0, arangate 0 — explicitamente zero, nunca são construídos.
  • araat 1, arafast 1, arassh 1 — unidades básicas que a IA deixa para segundo plano, em favor de alternativas de nível superior.

O mesmo padrão repete-se para as unidades tar*, ver* e zon* mais abaixo no ficheiro.

Bloco de limites

A seguir ao bloco de pesos vem um bloco de limites paralelo:

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
…

Repare na assimetria: aradrag tem peso 25 (prioridade alta) mas limite 1 (nunca mais de um). É assim que a IA do TA:K constrói em direção a uma unidade de herói: o peso alto faz com que seja construída cedo, o limite baixo mantém razoável a composição do exército.

Estatísticas dos perfis

O default.txt e os ficheiros das missões da campanha seguem todos a mesma forma:

Perfil Linhas Weight Linhas Limit Planos
ai/default.txt 104 104 0
ai/mission06.txt 104 104 0
ai/mission08.txt (missão do Iron Plague) 161 162 0

Os ficheiros das missões do Iron Plague têm tabelas de pesos/limites mais ricas porque cobrem as unidades Creon (prefixo CRE) que o default.txt do jogo base omite.

Como o kbot trata os ficheiros sem plan

O ai.Parse do kbot-io põe todas as linhas anteriores à primeira linha plan em AIFile.Preamble, que é o que o TA faz com elas (ver acima); para um perfil do TA: Kingdoms, ai.ParseWith(data, ai.ParseOptions{DefaultPlan: true}) lê-as para um único plano implícito que corresponde a todas as dificuldades. Os visualizadores do kbot mostram-nas num separador próprio, Before first plan, e dizem as duas coisas: o TA ignora-as quando uma partida começa, e os perfis do TA: Kingdoms, que não têm linhas plan, aplicam-nas em todas as dificuldades. O kbot não modela a forma como o TA: Kingdoms aplica pesos acima de 1.

O ai.IsAIFile() olha para a primeira palavra de cada linha: um ficheiro é um perfil quando alguma linha começa por uma diretiva escrita da forma habitual (uma linha plan que nomeie easy, medium, hard ou any, ou uma linha weight/limit cujo valor comece por um número). Isto deteta os perfis do TAK, que não têm plan, e os que usam tabulações como separador, sem tomar por perfil um .txt que apenas mencione "weight" ou "limit" no texto.


Armadilhas

Warning

O jogo não avisa de nada. Um nome de unidade mal escrito é lido como uma categoria que não corresponde a nenhuma unidade e não faz nada; um valor que não seja um número lê-se como 0 (e assim um limite proíbe o alvo); as linhas antes do primeiro plan são ignoradas no início da partida. O primeiro sinal de um perfil estragado costuma ser "a IA está a comportar-se de forma estranha". Os visualizadores do kbot assinalam cada um destes casos (ver abaixo).

  • Limit 0, ou qualquer limite negativo que não seja -1, impede a IA de construir esse alvo. -1 levanta o limite.
  • # termina uma linha em qualquer ponto, mesmo dentro de uma palavra; não há comentários de bloco. // só funciona porque uma linha cuja primeira palavra não é uma diretiva é ignorada e as palavras a seguir ao valor também.
  • Um peso acima de 1 nunca leva uma unidade além de 100 %. Só pode repor uma unidade que um peso de categoria tenha reduzido antes.
  • A primeira linha que nomeia uma unidade bloqueia-a. Coloque as linhas específicas de unidades depois das linhas de categoria que devem afinar.
  • O espaço em branco entre tokens só conta como separador: tabulações, espaços simples ou vários espaços funcionam todos da mesma forma.
  • Não há suporte para secções aninhadas ou partilhadas. Cada bloco plan tem de voltar a declarar todos os pesos/limites que lhe interessam.

O que o kbot mostra

O explorador de recursos do estúdio (separador AI Profile) e o describe do kbot mount leem o perfil como o jogo o lê:

  • Before first plan: as linhas do preâmbulo, assinaladas como ignoradas quando uma partida começa.
  • Um separador por plano, com cada alvo marcado como unit, category ou all units em relação aos units/*.fbi da instalação (nome e Category=). Uma categoria que nenhuma unidade tem, que é como se lê um nome de unidade mal escrito, é marcada como matches no unit. Os pesos aparecem como multiplicadores, com uma barra para a percentagem com que fica uma unidade que estava a 100 %; os limites aparecem como ∞ Unlimited, Disabled (0 ou qualquer valor negativo que não seja -1) ou Max: N.
  • Linhas que o jogo lê de outra forma: os diagnósticos do kbot-io, como uma palavra de valor que não é um número (O lê-se como 0) ou palavras depois do valor. Uma palavra de valor que não seja o número que o jogo lê aparece ao lado dele (written "O"); outra grafia do mesmo número, como .1 ou 0.10, não aparece.
  • At game start (estúdio; o kbot mount imprime as contagens): para easy, medium e hard, todas as unidades cujo peso ou limite o perfil altera, com 🔒 nos valores que uma linha de unidade bloqueou.

Tamanhos típicos

Métrica Intervalo observado nos perfis da Cavedog
Tamanho do ficheiro 1–4 KB
Planos por ficheiro 3 (easy/medium/hard)
Diretivas Weight por plano 20–80
Diretivas Limit por plano 0–10

Ver também

  • TDF — os metadados de mapa do .ota que escolhem um perfil de IA.
  • Glossário — lado, categoria.