Todas as páginas de formatos ↓
Gráficos e multimédia

TAF / TSF — Animações truecolor do TA: Kingdoms

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

O TAF guarda as animações de sprites truecolor do Total Annihilation: Kingdoms: efeitos de feitiços, explosões, bolas de fogo, anéis mágicos, sprites de água e os fundos animados dos menus. Reutiliza a disposição do contentor GAF do Total Annihilation, mas troca os píxeis de 8 bits indexados na paleta por ARGB de 16 bits, por isso um TAF traz a sua própria cor e um verdadeiro canal alfa, sem precisar de paleta externa. O TSF é a forma de texto legível da mesma animação: um script delimitado por chavetas que o carregador da interface lê diretamente.

sequência FireballA de fireballa_1555.taf    um único fotograma de BlueFire com margens de alfa suave

Tip

Experimente por si.

kbot taf list   anims/manabomb_1555.taf                                 # sequence + frame count
kbot taf export anims/fireballa_1555.taf --format gif -o fireball.gif    # animated preview
kbot taf sheet  anims/manabomb_1555.taf --cols 5 -o manabomb-sheet.png   # contact sheet
kbot taf decompile anims/manabomb_1555.taf --target ./manabomb           # → TSF + PNG layers

Todas as opções estão na referência de kbot taf / kbot tsf da linha de comandos.

A partir de Go. Use formats/tsf:

import "github.com/coreprime/kbot/formats/tsf"

data, _ := os.ReadFile("anims/manabomb_1555.taf")
taf, _ := tsf.ParseTAF(data)
fmt.Println(taf.Name, len(taf.Frames))
img, _ := taf.FrameImage(0)   // *image.NRGBA, full alpha preserved

Visão geral

┌─ Header (12B) ─┐
│ ver  1  pad    │   ver = 0x00010100, exactly one sequence
└────────┬───────┘
         ▼
┌─ Entry pointer ─┐  1 × uint32 absolute offset → SequenceHeader
└───┬─────────────┘
    ▼
┌─ SequenceHeader (40B) ─┐
│ frameCount, name[32]   │
└─────────┬──────────────┘
          ▼
┌─ FrameListItem (8B) × frameCount ─┐  ptr + tick duration
└───┬───────────────────────────────┘
    ▼
┌─ FrameInfo (24B) ─┐
│ size, origin,     │
│ format(4/5),      │   ← the GAF "compressed" byte, repurposed
│ layers=0, flag,   │
│ ptrPixelData      │
└─────┬─────────────┘
      ▼
┌─ Pixel data: Width×Height × uint16 ─┐  raw ARGB4444 or ARGB1555
└──────────────────────────────────────┘

Um TAF é uma única sequência de animação: um vetor de fotogramas, cada um com um retângulo de largura × altura de píxeis truecolor de 16 bits little-endian, um ponto de origem e uma duração em ticks. Não há compressão nem camadas ao nível binário: cada fotograma é um mapa de bits simples, não comprimido.

Note

O TAF é o contentor GAF com outro payload de píxeis. Se já leu a página do GAF, o cabeçalho, a tabela de entrada, o cabeçalho da sequência e a lista de fotogramas são-lhe familiares byte a byte. Só mudam a interpretação de FrameInfo e a codificação dos píxeis. Os dois coexistem sob a extensão .taf: o TA: Kingdoms inclui ficheiros .taf com paleta (leia-os como um GAF) e ficheiros .taf truecolor (esta página). O kbot distingue-os pelo byte de formato de cada fotograma; veja Distinguir os dois.


Cabeçalho (12 bytes)

typedef struct {
    uint32 Version;        // 0x00010100 — identical to the GAF version word
    uint32 SequenceCount;  // Always 1 for a truecolor TAF
    uint32 Unknown1;       // Always 0
} TAFHeader;
Campo Notas
Version 0x00010100, a mesma palavra que um GAF do TA tem. Valide-a antes de confiar em qualquer deslocamento.
SequenceCount Sempre 1. Seguido imediatamente de um deslocamento absoluto uint32 que aponta para o SequenceHeader. Um ficheiro com várias sequências não é um TAF truecolor.
Unknown1 Sempre zero; escreva zero ao gravar.

Sequência (40 bytes)

typedef struct {
    uint16 FrameCount;
    uint16 Unknown1;       // Always 1
    uint32 Unknown2;       // Always 0
    char   Name[32];       // NUL-padded, case-preserved
} TAFSequence;

Seguem-se FrameCount × FrameListItem:

typedef struct {
    uint32 PtrFrameInfo;   // → FrameInfo
    uint32 Duration;       // Game ticks (30 ticks = 1 second)
} FrameListItem;

Warning

O campo de nome de 32 bytes pode trazer lixo depois do terminador. Vários TAF da versão comercial deixam bytes de buffer não inicializados depois do NUL; o kbot preserva exatamente os 32 bytes, para que uma ida e volta análise → serialização seja idêntica byte a byte, mas só o texto até ao primeiro NUL é o nome verdadeiro.


Fotograma (24 bytes de informação + payload)

typedef struct {
    uint16 Width;
    uint16 Height;
    int16  OriginX;        // Render anchor, may be negative
    int16  OriginY;
    uint8  Transparency;   // 0x08: always 0 (alpha lives in the pixels)
    uint8  Format;         // 0x09: 4 = ARGB4444, 5 = ARGB1555
    uint8  LayerCount;     // 0x0A: always 0 (no sub-frames)
    uint8  Flag;           // 0x0B: 0x00 or 0xFF, meaning unconfirmed
    uint32 Unknown2;       // 0x0C: always 0
    uint32 PtrPixelData;   // 0x10: → raw pixel bytes
    uint32 Unknown3;       // 0x14: always 0
} FrameInfo;

É aqui que o TAF se afasta do GAF. Num FrameInfo de GAF, o deslocamento 0x09 é a flag Compressed e os deslocamentos 0x0A–0x0B são um LayerCount de 16 bits. Um TAF truecolor reutiliza esses mesmos bytes com este significado:

Deslocamento Significado no GAF Significado no TAF
0x08 TransparencyIndex Transparency — não usado, sempre 0
0x09 Compressed (0/1) Format — 4 (ARGB4444) ou 5 (ARGB1555)
0x0A byte inferior de LayerCount LayerCount — sempre 0
0x0B byte superior de LayerCount Flag — 0x00 ou 0xFF, finalidade desconhecida

OriginX / OriginY são a âncora usada ao copiar (blit) o fotograma: normalmente o centro do efeito, por isso uma explosão de 50×48 tem a origem em 25,24. O kbot mantém o byte Flag tal e qual, para idas e voltas exatas ao byte, embora o seu significado não esteja confirmado no conjunto de recursos da versão comercial.

Dados de píxeis

PtrPixelData aponta para exatamente Width × Height valores uint16 little-endian: 2 bytes por píxel, de cima para baixo, da esquerda para a direita, sem compressão e sem cabeçalhos de linha. Os 16 bits descodificam-se de acordo com o Format do fotograma:

ARGB4444 (Format == 4)

 bit 15 ──────────────────────────── bit 0
┌─────┬─────┬─────┬─────┐
│  A  │  R  │  G  │  B  │   4 bits each
└─────┴─────┴─────┴─────┘
  15-12  11-8   7-4   3-0

Cada canal de 4 bits é alargado a 8 bits por replicação de bits (v<<4 | v), por isso 0xF → 0xFF e 0x0 → 0x00. A expansão é exatamente invertível, o que permite ao kbot fazer a ida e volta dos píxeis sem perdas.

ARGB1555 (Format == 5)

 bit 15 ──────────────────────────── bit 0
┌─┬───────┬───────┬───────┐
│A│   R   │   G   │   B   │   1 + 5 + 5 + 5
└─┴───────┴───────┴───────┘
 15  14-10   9-5    4-0

O bit de alfa único é tudo ou nada (0 → totalmente transparente, 1 → totalmente opaco); cada canal de cor de 5 bits é alargado por replicação (v<<3 | v>>2). Use ARGB1555 nos sprites de margens nítidas que só precisam de um recorte de 1 bit, e ARGB4444 quando precisar de 16 níveis de alfa suave (fumo, brilhos, desvanecimentos).

Important

O TAF não precisa de paleta. Ao contrário do GAF, que só guarda índices e depende de palettes/palette.pal ou de um PCX auxiliar do TA:K, cada píxel de um TAF já contém a sua própria cor e o seu alfa. A renderização é uma expansão direta de 16 bits → 32 bits, sem qualquer tabela de consulta.


Distinguir os TAF com paleta dos truecolor

Os dois tipos de .taf partilham o cabeçalho e a palavra de versão do GAF, por isso não é possível distingui-los pelos primeiros 12 bytes. O que os distingue é o byte Format/Compressed do fotograma, no deslocamento 0x09 de FrameInfo:

Byte em 0x09 O ficheiro é Ler com
0 ou 1 Animação com paleta ao estilo GAF (um valor de 0/1 significa não comprimido/comprimido) O carregador de GAF + uma paleta
4 ou 5 Animação truecolor (ARGB4444 / ARGB1555) Esta página (formats/tsf)

kbot taf valida o byte e recusa um ficheiro com paleta com um erro claro; nesse caso, recorra a kbot gaf. A maioria dos TAF truecolor do TA:K também segue uma convenção de nomes, com um sufixo _4444 ou _1555 (manabomb_1555.taf, bluefire_4444.taf), mas quem decide é o byte de formato, não o nome.


TSF — a forma de texto

O TSF (TAF Source Format) é a mesma animação expressa num script ao estilo INI, delimitado por chavetas. O carregador da interface do TA: Kingdoms lê o TSF diretamente para os fundos dos menus, e é o formato de intercâmbio que o kbot gera quando descompila um TAF: uma secção por animação, um Frame aninhado por fotograma e um Layer por fotograma, que refere um ficheiro de imagem externo.

/* anims/titlescreen.tsf — abridged */
[JPGTest]
{
    Looping = 0;
    [Frame0]
    {
        Delay = 0;
        [Layer0]
        {
            AnchorX = 0;
            AnchorY = 0;
            Filename = TitleScreen.jpg;
        }
    }
    [Frame1] { /* … */ }
}
Token Corresponde a Notas
[Name] { … } A sequência de animação Uma por documento; Name passa a ser o nome da sequência do TAF.
Looping (indicativo) Sugestão para o autor; o TAF binário não tem campo de ciclo.
[FrameN] Um Frame Delay é a duração em ticks do jogo.
Format Frame.Format ARGB4444 (por omissão) ou ARGB1555.
[LayerN] A imagem do fotograma Filename refere um PNG/JPG externo; AnchorX/Y passam a ser a origem do fotograma.

Um TAF compilado achata a única camada de cada fotograma num mapa de bits truecolor. O kbot espera exatamente uma camada por fotograma (a composição de várias camadas é uma comodidade de criação da interface que o compilador resolve no momento da construção); kbot tsf lint assinala tudo o que não compile sem problemas.

Tip

Inspecione um TSF sem tocar nas imagens.

kbot tsf info anims/titlescreen.tsf   # animation, frames, layer filenames
kbot tsf lint anims/titlescreen.tsf   # shape check; non-zero exit on errors

lint só valida a estrutura; use kbot taf compile para pôr à prova todo o processo de carregamento das imagens.


Exemplo comentado — manabomb_1555.taf

os dez fotogramas de manabomb dispostos numa grelha

$ kbot taf info anims/manabomb_1555.taf
TAF: anims/manabomb_1555.taf
Sequence:  "manabomb"
Frames:    10
Duration:  20 ticks (0.67s)

#  Size   Origin  Format    Duration  Flag
─  ────   ──────  ──────    ────────  ────
0  50x48  25,24   ARGB1555  2         0x00
1  50x48  25,24   ARGB1555  2         0x00
...
9  50x48  25,24   ARGB1555  2         0x00

Dez fotogramas de 50×48, cada um ancorado no centro (25,24) e mostrado durante 2 ticks: uma estrela de explosão de ⅔ de segundo. O ficheiro inteiro tem 48 376 bytes: 50 × 48 × 2 = 4,800 bytes de píxeis por fotograma × 10, mais o cabeçalho, o cabeçalho da sequência, a lista de fotogramas e dez registos de informação de 24 bytes.


Fluxos de trabalho na linha de comandos

A árvore kbot taf cobre a inspeção, a renderização, a conversão e o ciclo de compilação TAF↔TSF; kbot tsf trata da forma de texto. Todos os comandos resolvem a entrada através do contexto do kbot ativo ou de uma montagem --vfs explícita, exatamente como kbot gaf e kbot studio, por isso nomes de ficheiro simples como manabomb_1555.taf são procurados em todos os arquivos montados.

Inspecionar e renderizar

kbot taf info   anims/bluefire_4444.taf            # per-frame table
kbot taf list   anims/bluefire_4444.taf            # one-line summary
kbot taf render anims/bluefire_4444.taf --frame 4 -o frame4.png
kbot taf sheet  anims/bluefire_4444.taf --cols 6 --bg "#202830" -o sheet.png
kbot taf export anims/bluefire_4444.taf --format apng -o bluefire.png   # or --format gif

export usa APNG por omissão, que mantém o canal alfa completo; --format gif quantiza para uma tabela de 255 cores mais uma posição transparente (um recorte de 1 bit), para pré-visualizações e clientes de chat.

Ida e volta descompilar ↔ compilar

kbot taf decompile anims/manabomb_1555.taf --target ./manabomb
#   → manabomb/manabomb.tsf  +  manabomb_0.png … manabomb_9.png

kbot taf compile ./manabomb/manabomb.tsf --images ./manabomb -o rebuilt.taf
kbot taf diff anims/manabomb_1555.taf rebuilt.taf      # exits 0 — identical

decompile escreve um TSF e um PNG por fotograma; compile volta a lê-los para um TAF binário. Em qualquer TAF que o kbot tenha analisado, a ida e volta é idêntica byte a byte; tanto kbot taf roundtrip como kbot taf diff o verificam.

Importar de formatos comuns

kbot taf from-gif   boom.gif   --format argb4444 --name Boom        -o boom.taf
kbot taf from-sheet strip.png  --frame-width 64 --frame-height 64 \
                               --count 8 --delay 3 --format argb1555 -o strip.taf

from-gif achata um GIF animado num TAF truecolor e respeita os modos de descarte e os atrasos de cada fotograma; from-sheet corta em fotogramas uma tira de sprites PNG/JPG em grelha fixa. Ambos permitem escolher o formato de píxel de destino.

Validar

kbot taf lint anims/manabomb_1555.taf   # structural findings; non-zero exit on errors

Ferramentas MCP

A mesma interface está disponível através do servidor MCP, para que um agente possa inspecionar e mostrar animações diretamente:

Ferramenta Finalidade
taf_info JSON completo por fotograma: nome, tamanhos, origens, formatos, durações.
taf_list Resumo JSON de uma linha.
taf_render Renderiza um fotograma e devolve-o embutido como PNG (e, opcionalmente, também o grava).
taf_sheet Renderiza todos os fotogramas numa folha de contactos, devolvida embutida como PNG.
taf_export Escreve um GIF animado ou um APNG no disco.
taf_lint Diagnósticos estruturais em JSON.
tsf_info Resume um documento TSF (animação, fotogramas, nomes dos ficheiros das camadas).
tsf_lint Verifica a forma de um documento TSF.

taf_render e taf_sheet devolvem um bloco de conteúdo de imagem, para que um modelo possa pré-visualizar um efeito de feitiço sem uma ida e volta separada para ler um ficheiro. Os caminhos são resolvidos na pasta game-data configurada, da mesma forma que em todas as outras ferramentas MCP do kbot.


Armadilhas

Warning

.taf tem dois significados. Um .taf pode ser um GAF com paleta ou uma animação truecolor. Verifique sempre o byte de formato do fotograma (0x09), e não a extensão ou o nome do ficheiro; veja Distinguir os dois.

  • Exatamente uma sequência. Um TAF truecolor tem sempre uma única animação; um SequenceCount diferente de 1 significa que está a olhar para outro tipo de ficheiro (provavelmente com paleta).
  • Nunca há compressão. Cada fotograma é um mapa de bits simples de Width×Height com 16 bits. Não há um caminho RLE como no GAF: os grandes efeitos de chamas (composite02flame) chegam a ~600 KB precisamente porque nada é comprimido.
  • O campo do nome pode ter lixo. Os bytes depois do NUL terminador não estão inicializados em vários ficheiros da versão comercial; preserve os 32 bytes para uma ida e volta exata, mas leia só até ao NUL.
  • O byte de flag 0x0B não tem explicação. Foi observado como 0x00 ou 0xFF. O kbot mantém-no tal e qual; não o normalize, ou as idas e voltas deixam de coincidir.
  • A exportação para GIF perde informação. O GIF só suporta um recorte de 1 bit e 255 cores: o alfa suave do ARGB4444 passa a margens nítidas. Use APNG para preservar o verdadeiro canal alfa.
  • Um Delay / Duration de 0 é válido. Tal como no GAF, um fotograma de zero ticks é orientado por eventos (o exemplo de menu JPGTest usa Delay = 0 para um fundo estático). Não o "corrija" para um valor predefinido.

Tamanhos típicos

Recurso Intervalo observado nos TAF do TA:K
Efeito pequeno (bluefire_4444, 12 fotogramas de mais ou menos 32) ~30–60 KB
Explosão (manabomb_1555, 10 × 50×48) ~48 KB
Bola de fogo / feitiço (fireballa_1555) ~50–120 KB
Grande chama composta (composite02flame) ~600 KB (o truecolor sem compressão acumula)
Dados de píxeis por fotograma Width × Height × 2 bytes, exatamente

Ver também

  • GAF — o contentor com paleta em que o TAF assenta; leia-o primeiro e use-o para os ficheiros .taf com paleta.
  • PCX — como os recursos do TA:K com paleta obtêm as suas cores (o TAF truecolor não precisa de nenhuma).
  • Interface do TA:K — o sistema de menus cujo carregador usa o TSF diretamente para os fundos animados.
  • Formatos do TA e do TA:K — o que os dois jogos partilham e onde divergem.
  • Glossário — origem, tick, subfotograma.