Criar um cérebro
Um .oabrain que joga num lugar de computador: a pasta, cada chave do manifesto, as tags, os níveis, a visão total, onde o script roda, as cotas e o que acontece quando ele para.
Este capítulo resume docs/brains/oabrain-standard.md, docs/brains/authoring.md e docs/playing-with-brains.md. Esses documentos são o texto normativo.
O que é um cérebro
O computador do próprio motor continua sendo o padrão e continua no motor. Um cérebro joga num lugar de computador, e só num lugar que um jogador definiu para ele. Um ID de cérebro vazio é esse jogador integrado. Um lugar sem cérebro, um cérebro que não serve e um cérebro que para são todos jogados por esse mesmo jogador. Classic é escrito em Lua e joga como esse jogador. Ele é a documentação desse jogador, não um substituto.
Só a máquina que põe o computador no lugar roda o script, então os outros jogadores não precisam instalar nada. As máquinas deles espelham as unidades do lugar. Uma gravação reproduzida não roda o script. Um cérebro é código-fonte Lua e dados. Ele não tem código nativo, arquivo, rede nem relógio. A visão total é uma flag do manifesto. Um cérebro pode defini-la e pode jogar com ela numa partida em rede, e o lugar mostra a flag.
O pacote
Um cérebro é um arquivo .oabrain, ou a pasta em que esse arquivo se descompacta. O manifesto usa o YAML estrito de um perfil de mod: um documento, um mapeamento de nível superior, sem âncoras e sem escalares de bloco. O topo do pacote contém oabrain.yaml. Ao lado dele, cada arquivo é um destes. Um arquivo fora dessa lista é recusado.
my-brain.oabraino arquivo que um jogador obtém├─ oabrain.yamlobrigatório o manifesto, no máximo 256 KiB├─ brain.luao script de entrada. O nome padrão é brain.lua. entry indica outro, e esse arquivo precisa estar no pacote├─ lua/mais código-fonte Lua. require só lê estes arquivos. Cada parte tem letras minúsculas, dígitos e _├─ nets/uma rede que o manifesto cita, nets/ e um nome-base terminado em .oann├─ data/uma tabela de dados, a uma pasta de profundidade: .csv, .tdf, .json ou .txt├─ icon.pnga imagem, só quando icon a indica. Sem essa chave, o arquivo fica fora da lista├─ README.mduma nota no topo. O jogo não a carrega└─ LICENSEa licença no topo. O nome licence, e um readme numa subpasta, ficam fora da listaA comparação ignora maiúsculas e minúsculas nas letras ASCII, exceto onde o padrão diz que os bytes precisam coincidir. brain.lua fica fora da lista quando entry indica outro arquivo. Um arquivo Lua tem no máximo 1 MiB. O ícone é um PNG quadrado, com no máximo 256 pixels de lado e 256 KiB. O OA instala um cérebro em Brains/ seguido do ID do manifesto.
O manifesto
O leitor reúne todas as regras violadas e deixa o manifesto inalterado quando alguma é violada. Uma chave que o padrão não lista é recusada. Uma chave de perfil pertence a um mod. Uma chave de mutador é recusada como chave de mutador. Ponha a versão entre aspas, porque um 1.0 solto é um número, e ponha o asterisco entre aspas, porque um asterisco solto é um alias de YAML.
| Chave | Obrigatório | O que faz |
|---|---|---|
oabrain | sim | O formato. O inteiro 1. 1.0 e um 1 entre aspas são recusados. |
id | sim | Kebab-case em minúsculas, de 1 a 64 bytes. Sem hífen no início, no fim ou duplicado. O nome da pasta em Brains/. |
name | sim | De 1 a 64 bytes, sem caractere de controle. O nome que os jogadores veem. |
version | sim | Entre aspas, de uma a três partes, como uma versão de mutador, por exemplo "2.0". Um número simples é recusado. 2, 2.0 e 2.0.0 são considerados iguais. |
author | sim | Um mapeamento. name é obrigatório, de 1 a 128 bytes. email é opcional. |
description | sim | Obrigatória, de 1 a 2.000 bytes. Quebra de linha é permitida. Qualquer outro caractere de controle é recusado. A primeira linha, cortada em 200 bytes, é o resumo. |
homepage | não | Um endereço http ou https. |
icon | não | Só icon.png, a imagem no topo do pacote. Qualquer outra coisa é recusada. |
tags | sim | De 1 a 4 das nove tags abaixo, sem repetição. |
works-with | sim | De 1 a 32 condições, sem ID repetido. Um asterisco significa qualquer mod e o jogo base, e então é a única entrada. ta-3.1c significa o jogo base sem mod. Qualquer outro ID é um mod, com uma faixa de versões opcional. |
requires | não | Só engine e expansions. engine é uma faixa, entre aspas quando começa com o sinal de maior. expansions tem de 1 a 16 IDs de conjunto de conteúdo. Um cérebro não pode exigir um mutador. |
levels | sim | De 1 a 6 níveis. Cada mapeamento tem exatamente id, name e difficulty. |
fullAwareness | não | true ou false. Se ausente, vale false. Um true entre aspas é recusado. |
networks | não | De 1 a 16, cada uma com exatamente id, file e sha256. file é nets/ e um nome-base terminado em .oann. sha256 são 64 dígitos hexadecimais minúsculos entre aspas. |
options | não | No máximo 16, com as regras de opção do mutador. Uma opção toggle é true ou false, uma number é um número, e uma choice é o seu texto. me.options as lê. |
strings | não | No máximo 16 idiomas. Um idioma pode conter name, description, options, labels e levels. |
entry | não | Um arquivo Lua no topo do pacote, com nome em letras minúsculas, dígitos e _. Se ausente, vale brain.lua. |
As nove tags
Uma tag é uma destas nove, comparada byte a byte. Mais de quatro, quando a regra comum de tags já passou, é um problema à parte. Uma tag que não é uma das nove é recusada.
| Chave |
|---|
classic |
economy |
rush |
turtle |
air |
naval |
learned |
teaching |
experimental |
Níveis e dificuldade
levels é uma lista de 1 a 6 mapeamentos. Cada um tem exatamente id, name e difficulty, todos obrigatórios. id é kebab-case em minúsculas, de 1 a 32 bytes, e nenhum id se repete. name tem de 1 a 64 bytes, sem caractere de controle. difficulty é easy, medium ou hard, byte a byte.
Esses três nomes são os valores 0, 1 e 2. Um lugar que escolhe o nível usa esse valor como regra de renda, a mesma dificuldade que o jogo já usa.
Visão total
fullAwareness é true ou false. Se ausente, vale false. Um cérebro com a flag vê unidades que um lugar na névoa não veria, como faz o computador integrado, e suas verificações de local de construção não precisam de um jogador posicionando a construção. A flag é permitida numa partida em rede. A Biblioteca mostra Vê todas as unidades do mapa, como o computador do próprio Total Annihilation. A flag é do próprio manifesto. Ela não é concedida pelo ID do pacote, e não é uma das coisas que só o Classic recebe.
Onde um cérebro roda
Só a máquina que põe o computador no lugar precisa do pacote, e só ela roda o script. Um lugar é um jogador do computador desta máquina. Um lugar humano é recusado. game.mode é skirmish, campaign ou network.
| Situação | O que roda |
|---|---|
| Escaramuça | Cada lugar de computador que esta máquina joga, quando um jogador definiu um cérebro nele. Um ID vazio é o computador integrado. |
| Missão de campanha | O lugar da campanha segue o cérebro padrão que o jogador definiu. Uma missão não ignora esse padrão. |
| Partida em rede | A máquina dona do lugar de computador roda o cérebro, inclusive com visão total. As outras máquinas não rodam. |
| Jogo salvo carregado depois | O jogo salvo registra cada lugar. O padrão diz o que acontece quando o pacote está faltando ou a versão é diferente. |
| Gravação reproduzida | A gravação guarda o texto dos cérebros. A reprodução aplica os pacotes de rede gravados. Ela não põe nenhum cérebro num lugar e não chama seus hooks. |
| Deathmatch ou torneio | O início da partida não põe nenhum jogador do computador. |
O cérebro que um lugar usa não entra no hash da simulação. Duas partidas que diferem só no cérebro escolhido mantêm o mesmo hash do estado da partida. Os valores dos ajustes ai.* do mod fazem parte do perfil do mod que esse hash cobre, então eles continuam chegando a todas as máquinas.
As cotas de execução
Um cérebro roda como Lua num sandbox. Dois cérebros não compartilham módulos, globais nem cotas. O script não tem arquivo, relógio, ambiente, processo nem rede. Todo trecho é carregado como texto. pcall e xpcall não conseguem manter viva uma fase esgotada. Um turno é uma chamada que consome da reserva, no ponto de controle do lugar, depois da varredura de unidades. As ordens que um hook dá valem no tick seguinte.
| Cota | Valor |
|---|---|
| Instruções em load, fits, start, save e report | 50,000,000 |
| Instruções que cada tick acrescenta | 2,000,000 |
| Ticks que a reserva pode acumular, incluindo o atual | 30, então o saldo começa em 60,000,000 |
| Memória do Lua | 64 MiB (67,108,864 bytes). Ela não é zerada entre as fases. |
| Memória das redes | 64 MiB, separada do teto do Lua |
| Tempo real de uma fase que não é um turno, em milissegundos | 10,000 |
| Tempo real de um turno, em milissegundos | 250 |
| Uma string, em bytes | 65,536 |
Quando um cérebro falha
Um cérebro para por um erro num hook ou num timer, uma cota de instruções esgotada, o limite de segurança de tempo real, o teto de memória do Lua, uma string além de 65.536 bytes ou um carregamento que o lugar recusa. Um turno que falha fecha o sandbox e limpa os hooks antes de esse turno retornar. O turno que falhou ainda conta como jogado. O tick de ordens seguinte não tem hooks, então o computador integrado assume. Um cérebro recusado, que não consegue iniciar ou que não serve nunca tem hooks, então esse jogador joga desde o começo. O aviso usa o nome do manifesto e o motivo, cortado em 160 bytes:
- `{brain} stopped ({reason}); the engine plays this seat on`
- `{brain} could not start ({reason}); the engine plays this seat`
- `{brain} does not fit this game ({reason}); the engine plays this seat`
Quando o lugar não tem um motivo próprio, o motivo é the brain could not be seated. Um jogador derrotado simplesmente deixa de ser chamado. O sandbox fecha junto com a partida.