Toutes les pages de formats ↓
Graphismes et médias

TAF / TSF — animations truecolor de TA: Kingdoms

Source : coreprime/kbot @ 0ab97bf · Modifier sur GitHub

Le TAF stocke les animations de sprites truecolor de Total Annihilation: Kingdoms : effets de sorts, explosions, boules de feu, anneaux magiques, sprites d'eau et fonds de menus animés. Il reprend la disposition du conteneur GAF de Total Annihilation, mais remplace les pixels 8 bits indexés dans une palette par de l'ARGB 16 bits : un TAF porte donc ses propres couleurs et un vrai canal alpha, sans palette externe. Le TSF est la forme texte lisible de la même animation : un script délimité par des accolades que le chargeur de l'interface lit directement.

séquence FireballA de fireballa_1555.taf    une frame de BlueFire aux bords alpha adoucis

Tip

Essayez vous-même.

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

Consultez la référence de kbot taf / kbot tsf de la CLI pour toutes les options.

Depuis Go. Utilisez 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

Vue d'ensemble

┌─ 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
└──────────────────────────────────────┘

Un TAF est une séquence d'animation unique — un tableau de frames, chacune étant un rectangle largeur × hauteur de pixels truecolor 16 bits en little-endian, avec un point d'origine et une durée en ticks. Il n'y a ni compression ni calques au niveau binaire : chaque frame est une image plate, non compressée.

Note

Le TAF est le conteneur GAF avec une autre charge utile de pixels. Si vous avez lu GAF, l'en-tête, la table des entrées, l'en-tête de séquence et la liste des frames vous seront familiers à l'octet près. Seules l'interprétation de FrameInfo et l'encodage des pixels changent. Les deux cohabitent sous l'extension .taf : TA: Kingdoms livre des fichiers .taf à palette (à lire comme des GAF) et des fichiers .taf truecolor (cette page). kbot les distingue grâce à l'octet de format de chaque frame — voir Distinguer les deux types.


En-tête (12 octets)

typedef struct {
    uint32 Version;        // 0x00010100 — identical to the GAF version word
    uint32 SequenceCount;  // Always 1 for a truecolor TAF
    uint32 Unknown1;       // Always 0
} TAFHeader;
Champ Remarques
Version 0x00010100, le même mot que dans un GAF de TA. Vérifiez-le avant de vous fier au moindre offset.
SequenceCount Toujours 1. Immédiatement suivi d'un offset absolu uint32 qui pointe sur le SequenceHeader. Un fichier à plusieurs séquences n'est pas un TAF truecolor.
Unknown1 Toujours zéro ; écrire zéro.

Séquence (40 octets)

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

Suivi de FrameCount × FrameListItem :

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

Warning

Le champ de nom de 32 octets peut contenir des déchets après le terminateur. Plusieurs TAF d'origine laissent des octets de tampon non initialisés après le NUL : kbot conserve les 32 octets exacts pour qu'un aller-retour lecture → sérialisation soit identique à l'octet près, mais seul le texte jusqu'au premier NUL constitue le vrai nom.


Frame (info de 24 octets + charge utile)

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;

C'est ici que le TAF s'écarte du GAF. Dans un FrameInfo de GAF, l'offset 0x09 est le flag Compressed et les offsets 0x0A–0x0B forment un LayerCount de 16 bits. Un TAF truecolor réutilise ces mêmes octets avec le sens suivant :

Offset Sens dans le GAF Sens dans le TAF
0x08 TransparencyIndex Transparency — inutilisé, toujours 0
0x09 Compressed (0/1) Format — 4 (ARGB4444) ou 5 (ARGB1555)
0x0A octet de poids faible de LayerCount LayerCount — toujours 0
0x0B octet de poids fort de LayerCount Flag — 0x00 ou 0xFF, rôle inconnu

OriginX / OriginY sont le point d'ancrage utilisé pour copier la frame à l'écran — en général le centre de l'effet : une explosion de 50×48 a donc pour origine 25,24. kbot conserve l'octet Flag tel quel pour des allers-retours exacts à l'octet près, bien que son sens ne soit pas confirmé sur l'ensemble des ressources d'origine.

Données de pixels

PtrPixelData pointe sur exactement Width × Height valeurs uint16 en little-endian — 2 octets par pixel, de haut en bas et de gauche à droite, sans compression ni en-têtes de ligne. Les 16 bits se décodent selon le Format de la frame :

ARGB4444 (Format == 4)

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

Chaque canal de 4 bits est étendu à 8 bits par réplication des bits (v<<4 | v) : 0xF → 0xFF et 0x0 → 0x00. L'extension est exactement inversible, ce qui permet à kbot de faire l'aller-retour des pixels sans perte.

ARGB1555 (Format == 5)

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

L'unique bit alpha est en tout ou rien (0 → entièrement transparent, 1 → entièrement opaque) ; chaque canal de couleur de 5 bits est étendu par réplication (v<<3 | v>>2). Utilisez l'ARGB1555 pour les sprites aux bords nets qui n'ont besoin que d'un détourage sur 1 bit, et l'ARGB4444 quand il vous faut 16 niveaux d'alpha progressif (fumée, halos, fondus).

Important

Le TAF n'a besoin d'aucune palette. Contrairement au GAF — qui ne stocke que des index et dépend de palettes/palette.pal ou d'un PCX compagnon de TA:K —, chaque pixel d'un TAF contient déjà sa propre couleur et son alpha. Le rendu est une simple extension 16 bits → 32 bits, sans table de correspondance.


Distinguer les TAF à palette des TAF truecolor

Les deux sortes de .taf partagent l'en-tête et le mot de version du GAF : impossible donc de les distinguer sur les 12 premiers octets. Le critère est l'octet Format/Compressed de la frame, à l'offset 0x09 du FrameInfo :

Octet en 0x09 Le fichier est À lire avec
0 ou 1 une animation à palette de style GAF (une valeur 0/1 signifie non compressé/compressé) le chargeur GAF + une palette
4 ou 5 une animation truecolor (ARGB4444 / ARGB1555) cette page (formats/tsf)

kbot taf vérifie cet octet et refuse un fichier à palette avec une erreur claire ; dans ce cas, tournez-vous vers kbot gaf. La plupart des TAF truecolor de TA:K suivent aussi une convention de nommage — un suffixe _4444 ou _1555 (manabomb_1555.taf, bluefire_4444.taf) —, mais c'est l'octet de format qui fait foi, pas le nom.


TSF — la forme texte

Le TSF (TAF Source Format) est la même animation exprimée sous forme de script de style INI, délimité par des accolades. Le chargeur d'interface de TA: Kingdoms lit le TSF directement pour les fonds de menus, et c'est le format d'échange que produit kbot quand vous décompilez un TAF : une section par animation, une sous-section Frame par frame, et un Layer par frame qui renvoie à un fichier image externe.

/* anims/titlescreen.tsf — abridged */
[JPGTest]
{
    Looping = 0;
    [Frame0]
    {
        Delay = 0;
        [Layer0]
        {
            AnchorX = 0;
            AnchorY = 0;
            Filename = TitleScreen.jpg;
        }
    }
    [Frame1] { /* … */ }
}
Jeton Correspond à Remarques
[Name] { … } La séquence d'animation Une par document ; Name devient le nom de la séquence du TAF.
Looping (indicatif) Indication pour l'auteur ; le TAF binaire n'a pas de champ de boucle.
[FrameN] Une Frame Delay est la durée en ticks de jeu.
Format Frame.Format ARGB4444 (par défaut s'il est omis) ou ARGB1555.
[LayerN] L'image de la frame Filename renvoie à un PNG/JPG externe ; AnchorX/Y deviennent l'origine de la frame.

Un TAF compilé aplatit l'unique calque de chaque frame en une seule image truecolor. kbot attend exactement un calque par frame (la composition de plusieurs calques est une commodité de création d'interface que le compilateur résout à la construction) ; kbot tsf lint signale tout ce qui ne se compilera pas proprement.

Tip

Inspecter un TSF sans toucher aux images.

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

lint ne vérifie que la structure ; utilisez kbot taf compile pour exercer toute la chaîne de chargement des images.


Exemple commenté — manabomb_1555.taf

les dix frames de manabomb disposées en grille

$ 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

Dix frames de 50×48, chacune ancrée en son centre (25,24) et affichée pendant 2 ticks : une étoile d'explosion de ⅔ de seconde. Le fichier entier fait 48 376 octets : 50 × 48 × 2 = 4,800 octets de pixels par frame × 10, plus l'en-tête, l'en-tête de séquence, la liste des frames et dix enregistrements d'info de 24 octets.


Utilisation en ligne de commande

L'arborescence kbot taf couvre l'inspection, le rendu, la conversion et le cycle de compilation TAF↔TSF ; kbot tsf couvre la forme texte. Chaque commande résout son entrée via le contexte kbot actif ou un montage --vfs explicite, exactement comme kbot gaf et kbot studio : des noms de fichiers nus comme manabomb_1555.taf sont donc cherchés dans toutes les archives montées.

Inspecter et rendre

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 produit par défaut de l'APNG, qui conserve tout le canal alpha ; --format gif quantifie vers une table de 255 couleurs plus un emplacement transparent (un détourage sur 1 bit), pour les aperçus et les clients de messagerie.

Aller-retour décompilation ↔ compilation

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 écrit un TSF plus un PNG par frame ; compile les relit pour produire un TAF binaire. Pour tout TAF que kbot a analysé, l'aller-retour est identique à l'octet près — kbot taf roundtrip et kbot taf diff le vérifient tous deux.

Importer depuis des formats courants

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 aplatit un GIF animé (en respectant ses modes de disposition et ses délais par frame) en un TAF truecolor ; from-sheet découpe en frames une bande de sprites PNG/JPG à grille fixe. Les deux vous laissent choisir le format de pixel cible.

Valider

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

Outils MCP

Les mêmes fonctions sont exposées par le serveur MCP, pour qu'un agent puisse inspecter et montrer les animations directement :

Outil Rôle
taf_info JSON complet par frame : nom, tailles, origines, formats, durées.
taf_list Résumé JSON d'une ligne.
taf_render Rend une frame et la renvoie en ligne sous forme de PNG (et peut aussi l'enregistrer).
taf_sheet Rend toutes les frames dans une planche contact, renvoyée en ligne sous forme de PNG.
taf_export Écrit un GIF animé ou un APNG sur le disque.
taf_lint Diagnostics structurels en JSON.
tsf_info Résume un document TSF (animation, frames, noms des fichiers de calques).
tsf_lint Vérifie la forme d'un document TSF.

taf_render et taf_sheet renvoient un bloc de contenu image : un modèle peut ainsi prévisualiser un effet de sort sans aller-retour supplémentaire de lecture de fichier. Les chemins sont résolus par rapport au dossier game-data configuré, comme pour tous les autres outils MCP de kbot.


Pièges

Warning

L'extension .taf est ambiguë. Un .taf peut être un GAF à palette ou une animation truecolor. Vérifiez toujours l'octet de format de la frame (0x09), pas l'extension ni le nom de fichier — voir Distinguer les deux types.

  • Exactement une séquence. Un TAF truecolor contient toujours une seule animation ; un SequenceCount différent de 1 signifie que vous avez affaire à un autre fichier (probablement à palette).
  • Jamais de compression. Chaque frame est une image plate de Width×Height en 16 bits. Il n'existe pas de chemin RLE comme dans le GAF : les grands effets de flammes (composite02flame) atteignent ~600 Ko justement parce que rien n'est compacté.
  • Le champ de nom peut contenir des déchets. Dans plusieurs fichiers d'origine, les octets qui suivent le NUL final ne sont pas initialisés ; conservez les 32 octets pour un aller-retour exact, mais ne lisez que jusqu'au NUL.
  • L'octet de flag 0x0B reste inexpliqué. On l'observe à 0x00 ou à 0xFF. kbot le conserve tel quel ; ne le normalisez pas, sinon les allers-retours ne correspondent plus.
  • L'export GIF perd de l'information. Le GIF ne peut contenir qu'un détourage sur 1 bit et 255 couleurs : l'alpha progressif de l'ARGB4444 devient des bords nets. Utilisez l'APNG pour conserver le vrai canal alpha.
  • Un Delay / Duration de 0 est valide. Comme dans le GAF, une frame de zéro tick est pilotée par les événements (l'exemple de menu JPGTest utilise Delay = 0 pour un fond statique). Ne le « corrigez » pas en une valeur par défaut.

Tailles typiques

Ressource Plage observée dans les TAF de TA:K
Petit effet (bluefire_4444, 12 × frames de ~32) ~30–60 Ko
Explosion (manabomb_1555, 10 × 50×48) ~48 Ko
Boule de feu / sort (fireballa_1555) ~50–120 Ko
Grande flamme composite (composite02flame) ~600 Ko (le truecolor non compressé finit par peser lourd)
Données de pixels par frame Width × Height × 2 octets, exactement

Voir aussi

  • GAF — le conteneur à palette sur lequel repose le TAF ; à lire en premier, et à utiliser pour les fichiers .taf à palette.
  • PCX — comment les ressources à palette de TA:K obtiennent leurs couleurs (le TAF truecolor n'en a pas besoin).
  • Interface de TA:K — le système de menus dont le chargeur utilise directement le TSF pour les fonds animés.
  • Formats TA et TA:K — ce que les deux jeux ont en commun et où ils divergent.
  • Glossaire — origine, tick, sous-frame.