Häufige Stolperfallen beim Modding und Parsen
Ein Spickzettel auf einer Seite mit den häufigsten Stolperfallen aus den Formatdokumenten von kbot. Wenn du einem Fehler nachjagst, der keinen Sinn ergibt, fang hier an. Jeder Punkt verlinkt auf die ausführlichere Erklärung auf der jeweiligen Formatseite.
Tip
Suchst du nach „mein Mod lädt nicht“? Die Semikolon-Regel für TDF (TDF / FBI / OTA, erster Punkt) ist für mehr Meldungen über „stilles Kaputtgehen“ verantwortlich als alle anderen Stolperfallen zusammen.
HPI / UFO / CCX / GP3
- Lose Dateien im Wurzelverzeichnis der Installation haben Vorrang vor
jedem Archiv. Leg
units/MYUNIT.fbiauf die Platte, und die Engine zieht sie allem intotala1.hpivor. Das Schichtungsdiagramm in hpi.md zeigt die vollständige Rangfolge. - Unter den Archiven gewinnt das zuerst eingehängte, und es werden nur
zehn
*.hpieingehängt. TA 3.1c hängtrev31.gp3ein, dann*.ccx,*.ufound die ersten zehn*.hpi, die sich öffnen lassen, jede Gruppe nach dem großgeschriebenen ASCII-Namen sortiert. Ein Mod, der alszz_mod.hpiausgeliefert wird, rangiert unter jedem Archiv der Verkaufsversion. Hat die Installation schon zehn*.hpi, die davor einsortiert werden, wird er nur noch über den CD-Scan eingehängt – unter allem anderen. Liefere Mods als.ufoaus. - Zeiger in HPI v1 beziehen sich absolut auf den Dateianfang, nicht auf
den Anfang des Verzeichnisses. Zieh nichts ab. Der Trick der
kanonischen Parser besteht darin, einen Puffer von
DirectorySizeByte anzulegen und das Verzeichnis entschlüsselt ab OffsetStarthineinzuschreiben, damit die Zeiger den Puffer direkt indizieren. Siehe Verzeichnisbaum. - Der Seed der Chiffre von HPI v1 läuft mit der Dateiposition mit. Du kannst einen Puffer nicht isoliert entschlüsseln – du musst wissen, von welchem absoluten Datei-Offset er stammt. Siehe Den Chiffrierschlüssel ableiten.
- Ist
DecryptKey == 0, wende die XOR-Chiffre gar nicht an. Manche selbst gebauten Archive werden unverschlüsselt ausgeliefert; wendest du die Chiffre trotzdem an, verwürfelst du, was bereits lesbar ist. - Die Prüfsumme der SQSH-Chunks wird über die verschlüsselten Bytes berechnet. Prüfe sie vor dem Entwürfeln. Siehe Komprimierte Chunks (SQSH).
- TA: Kingdoms verwendet HPI v2 (
Version == 0x00020000) mit einem anderen Aufbau – kein XOR, ein einziger SQSH-Chunk pro Datei. Lies den Abschnitt TA: Kingdoms – HPI v2, bevor du den v1-Parser an einem TAK-Archiv ausprobierst. - Spielstände mit dem Marker
BANKsind etwas ganz anderes – sie verwenden die HPI-Hülle wieder, aber der Inhalt ist serialisierter Spielzustand, kein Dateisystem. kbot dekodiert sie nicht. .gp3setzt den Patch rev3.1 voraus. Innen ist es nach wie vor HPI, aber ein ungepatchtes TA weigert sich, es einzuhängen.
TDF / FBI / OTA
- Jeder Wert muss mit
;enden. Fehlende Semikolons verschmelzen Werte stillschweigend über Zeilen hinweg und führen zu völlig falschen Einheitenwerten. Das ist die Ursache Nr. 1 für „meine Einheit hat seltsame Trefferpunkte / keine Beschreibung / falsche Kosten“. - Schlüssel unterscheiden nicht zwischen Groß- und Kleinschreibung,
Werte schon.
Side=armfunktioniert bei den meisten Abfragen, scheitert aber an jedem Mod-Code, derSideper String-Vergleich prüft. - Listenwerte sind durch Leerzeichen getrennt (
Category=COMMANDER MOBILE WEAPON) – nicht durch Kommas. Die Ausnahme istnumplayers=2,4,6,8,10in der OTA, das Kommas verwendet. - Boolesche Werte sind die Ganzzahlen
1/0, nichttrue/false. Die Engine akzeptiert nur die ganzzahligen Formen. - Bearbeite für Mods nie
sidedata.tdf, um Einheiten hinzuzufügen. Nimm stattdessen eine[MENUENTRY]-Registrierung indownload/<UNITNAME>.tdf– denselben Mechanismus, den Core Contingency verwendet. Siehe TDF:[MENUENTRY]und das Modding-Tutorial. Bmcode=0blendet eine Einheit aus dem Baumenü aus, auch wenn alles andere gültig ist. Fast immer willst duBmcode=1.- Eine Einheit, die bei keiner Baueinheit aufgeführt ist, kann nicht gebaut werden, auch wenn ihre FBI ansonsten gültig ist. Der häufigste Fehler der Art „meine neue Einheit existiert, ist aber nicht baubar“. Siehe Modding, Schritt 5.
- Die Verschachtelungstiefe von Abschnitten ist Konvention, keine
Spezifikation. Manche Werkzeuge gehen von 2 Ebenen aus; Waffen-TDFs
reichen 3 Ebenen tief (
[WEAPON][DAMAGE][category]).
TNT / SCT – Kartengelände
WidthundHeighteiner TNT zählen Attributzellen zu 16 px, weder Kacheln noch Pixel. Geteilt durch 2 ergibt sich die Zahl der Kacheln, mal 16 die Größe in Pixeln. Siehe TNT-Header.SeaLevel == 0bedeutet NICHT „kein Wasser“ – es bedeutet, dass der kleinstmögliche Wert auf der Schwelle liegt, also nichts unter Wasser ist. NimmSeaLevel = 1für wirklich trockene Karten.- Ein Objektwort einer TNT platziert nur dann ein Kartenobjekt, wenn es
kleiner als die Zahl der Einträge in der Objekttabelle ist.
0xFFFCist leer;0xFFFE(Lava Run, AC02),0xFFFDund jedes andere Wort ab der Tabellengröße platzieren nichts, und die Zelle bleibt bebaubar. - Die Auffüllung der Minikarte einer TNT verwendet Palettenindex
0x64, und die Größe des Kartenbereichs wird aus der Karte berechnet (längere Seite 252, Seitenverhältnis der sichtbaren Karte), nicht durch Suche nach der Auffüllung ermittelt. Das Spiel liest die gespeicherte Minikarte nur, wenn Bit 0 des Header-Worts bei0x2cgesetzt ist. Siehe TNT. - Die
.tntvon TA: Kingdoms verwendetIDVersion == 0x4000statt0x2000wie TA (TA liest außerdem einen älteren Aufbau0x1020).kbot tnt imageerzeugt bei TNTs von TAK nur Müll; der Kachel-Decoder ist TA-spezifisch. Siehe TA:K-Karten. - SCT-Sektionen müssen in beiden Dimensionen ein Vielfaches von 4 sein, damit TAE sie lädt. Das Format auf der Platte erlaubt andere Größen, aber der Editor lehnt sie mit „section misaligned“ ab.
- SCT V2 hat Höhenzellen zu 8 Byte, V3 solche zu 4 Byte. kbot akzeptiert beide; Mods, die mit dem Editor gebaut wurden, sehen nur V3.
3DO – Modelle
- Oben ist Y, nicht Z. Wer ein 3DO ohne Achsentausch in eine Engine mit Z nach oben importiert (Blender, modernes Unreal), sieht jede Einheit auf der Seite liegen.
- Untexturierte Primitive sind unsichtbar, sofern nicht
IsColored != 0gilt – der Pseudocodevisible = (texture != "") || (IsColored != 0)deckt beide Fälle ab. Der häufigste Fehler beim Rendern von 3DO. OffsetToSelectionPrimhat nur beim Wurzelobjekt eine Bedeutung; Kindobjekte müssen es auf-1(0xFFFFFFFF) setzen.- Die Festkomma-Skalierung ist
1 / 65536. Ein als0x00010000geschriebener Vertex entspricht 1,0 Welteinheiten; die unteren 16 Bit sind der Nachkommaanteil. - Vertices sind objektlokal, nicht global. Zwei Objekte können identische Vertex-Arrays haben – das ist gespiegelte Geometrie, keine gemeinsam genutzten Daten.
COB / BOS – Skripte
- Der Opcode von
call-scriptist0x10062000, NICHT0x10063000, wie manche Dokumente aus der Zeit vor 3.1 behaupten. Alte Decompiler, die0x10063000verwenden, erzeugen Unsinn – siehe die Opcode-Referenz. - Piece-Nummern in Opcodes sind Indizes in die Namenstabelle der Pieces, keine Strings. Die COB führt die Namen als String-Pool; die Laufzeitumgebung verwendet aus Geschwindigkeitsgründen Indizes.
SET_SIGNAL_MASKmeldet nur Interesse an – es beendet nichts. Erst das Senden vonsignal Xstoppt Skripte, deren MaskeXgesetzt hat. Die Lint-Regelsignal-never-signalledfindet Skripte, die eine Maske setzen, die niemand je signalisiert.- Cavedogs Scriptor setzt
CURRENT_SPEEDals Literal29ein, was Skripte im Stil vonMoveWatchernach einem Round-Trip kaputtmacht. Der Decompiler von kbot stellt den symbolischen Namen wieder her; wenn du einen Round-Trip durch Scriptor machen musst, setze Klammern:(get CURRENT_SPEED) > 5. - Sprung-Offsets sind Byte-Offsets relativ zu
OffsetToScriptCode, nicht relativ zur aktuellen Instruktion.JUMP 0x4Cbedeutet „springe zuOffsetToScriptCode + 0x4C“. - Die Portnummern von
GET_UNIT_VALUEunterscheiden sich zwischen TA und TA:K. Der Katalog von TA (der Decompiler von kbot benennt die Ports 1–20) ist in Anhang B dokumentiert.
GAF – Sprite-Animationen
- Eine Sequenz läuft nur dann in einer Schleife, wenn das untere Byte ihres Worts bei +2 gesetzt ist; bei 0 spielt sie einmal und hält an. Jede Originalsequenz speichert 1; ein Werkzeug, das 0 schreibt, friert also animierte Kartenobjekte ein.
- Frames in
textures/*.gafundanims/vismasks.gafmüssen roh sein. Das Spiel liest sie als einfache Pixel-Arrays. - Manche Sequenzen werden mit Frame-Dauern von
0ausgeliefert; das Spiel zeigt einen solchen Frame einen Tick lang. Setz sie nicht auf einen Standardwert, um sie zu „reparieren“. - Palettenindex 0 ist nicht von sich aus transparent. Transparent sind nur der Schlüssel eines rohen Frames und die Überspring-Läufe eines komprimierten Frames.
- Komprimierte Pixelzeilen können kürzer als
Widthsein. Das Spiel liest in die nächsten Bytes weiter; kbot füllt die Zeile mit transparenten Pixeln auf und warnt. Keine Originaldatei hat solche Zeilen. - Die Ursprünge der Ebenen sind Hotspots: Jede Ebene eines zusammengesetzten Frames wird so platziert, dass ihr Ursprung auf dem Ursprung des Frames liegt.
anims/terrain.gafundanims/vismasks.gafhaben in ihren HeadernVersion == 0. Das Spiel ignoriert das Versionswort.- Die
.tafvon TA: Kingdoms gibt es in zwei Arten. Eine.tafmit Palette IST ein GAF – dasselbe Format auf der Platte, nur dass TAK die Palette aus einer.pcxpro Seite holt statt aus der globalen Palette von TA. Eine Truecolor-.tafverwendet denselben Container, speichert aber 16-Bit-ARGB-Pixel und braucht keine Palette. Maßgeblich ist das Format-Byte des Frames (0/1= mit Palette,4/5= Truecolor), nicht die Endung – siehe TAF / TSF.
TAF / TSF – Truecolor-Animationen
.tafist mehrdeutig – mit Palette (wird als GAF gelesen) oder Truecolor (wird mitkbot tafgelesen). Prüfe immer das Format-Byte des Frames, nie den Dateinamen, auch wenn die meisten Truecolor-Dateien von TAK nach Konvention ein Suffix_4444/_1555tragen.- Der GIF-Export ist verlustbehaftet. GIF fasst nur eine 1-Bit-Maske
und 255 Farben; weiches ARGB4444-Alpha wird also zu harten Kanten. Nimm
APNG (
kbot taf export --format apng), um den echten Alphakanal zu erhalten. - Das Namensfeld des Frames und das Flag-Byte
0x0Bkönnen Datenmüll enthalten. Übernimm sie für einen bytegenauen Round-Trip unverändert; normalisiere nichts. - Ein
Delay/ eineDurationvon0ist zulässig – wie bei GAF ist ein Frame mit null Ticks ereignisgesteuert (statische Menühintergründe verwenden das). „Repariere“ das nicht.
PCX – Bilder
- TA ignoriert
BytesPerLine. Übliche Leser verwerfen die Auffüllung, wennBytesPerLine > Width; TA 3.1c dekodiert genauWidthByte pro Zeile, sodass Dateien mit Auffüllung im Spiel verschoben erscheinen. SchreibBytesPerLine == Widthund prüfe es mitkbot pcx describe. - TA lädt nur Version 5 und dekodiert jede Datei als 8-Bit-Daten mit einer einzigen Ebene.
- Literal-Bytes, bei denen die oberen zwei Bits gesetzt sind, müssen per
RLE maskiert werden. Ein nacktes Byte mit dem Wert
0xC0–0xFFist als Literal unzulässig; gib es als Lauf der Länge 1 aus (0xC1, 0xFFfür ein einzelnes0xFF). Wer das falsch behandelt, bringt das Dekodieren nach einer Zeile aus dem Tritt. - Das Spiel nimmt die letzten 768 Byte mit oder ohne den Marker
0x0Cals Palette; übliche Leser brauchen den Marker.
PAL / ALP / LHT / SHD – Paletten und Nachschlagetabellen
- Das 4. Byte pro Eintrag ist NICHT Alpha. Es ist ein unbenutztes
Füllbyte, das Cavedog immer auf
0x00gesetzt hat. Open-Source-Werkzeuge für Paletten, die es als Alpha behandeln, rendern die Palette nicht (alpha=0 → alles transparent). - Index 0 ist schwarz, nicht transparent. Gelände, Minikarten und Hintergründe zeichnen ihn deckend; Sprites wählen ihren eigenen Transparenzschlüssel.
- Eine leere oder fehlende
palette.palwird durchpalette.pcxersetzt (deren letzte 768 Byte); eine.pal, die länger als 1.024 Byte ist, wird bis Byte 1.024 gelesen. .alp/.lht/.shdsind KEINE RGB-Paletten –.alpist eine 256×256-Tabelle,.shd/.lhtsind 32×256-Tabellen, jeweils aus Palettenindizes, und das Spiel ignoriert eine Tabelle jeder anderen Größe (und baut sie neu auf). Rendert man sie mitkbot pal describe, kommt nur Müll heraus; nimm stattdessenkbot pal lookup.- Die Palette von TA enthält 13 doppelte RGB-Tripel. Wenn dein Editor beim Import Duplikate entfernt (manche tun das), verlierst du Einträge, und die Palette hat stillschweigend nur noch 243 Einträge.
FNT – Bitmap-Schriften
Offsets[c] == 0bedeutet „kein Glyph“, nicht „Glyph bei Offset 0“. Offset 0 liegt mitten im Header – Cavedog verwendet null als Sentinel-Wert.- Innerhalb jedes Bytes kommt das MSB zuerst. LSB zuerst ist bei modernen Bitmap-Schriften häufiger; geh nicht einfach davon aus.
- Der Bitstrom läuft zwischen den Zeilen durch – am Ende jeder Scanzeile gibt es keine Auffüllung.
KI-Profile
- KI-Dateien von TA: Kingdoms haben keine
plan-Direktiven – nur nackteweight-/limit-Zeilen. Der Parser von kbot öffnet einen implizitendefault-Plan; Leser sollten den fehlenden Block tolerieren. Siehe TA:K – Profile ohne plan. - Nirgends wird etwas geprüft. Falsch geschriebene Einheitennamen,
kaputte Gewichtswerte, Zeilen außerhalb von
plan– alles wird stillschweigend ignoriert. Das erste Anzeichen eines kaputten Profils ist „die KI verhält sich seltsam“, ohne jede Log-Meldung. - Kategorie-Aliasse (
PLANT,LEVEL3) „existieren“ nur, wenn mindestens eine Einheit sie inCategory=deklariert. Schreib versehentlichLEVL3, und die Direktive bewirkt stillschweigend nichts.
Sounds
- Eine fehlende WAV ist stumm, kein Fehler. Schreib versehentlich
select1=cmsdel1(vertauschte Buchstaben), und die Engine spielt nichts – kein Log, kein Ersatz. - Die Endung
.wavist in TDF-Werten implizit – schreib sie nie.select1=cmdsel1.wavwird zusounds/cmdsel1.wav.wavund findet nichts.
Besonderheiten von TA: Kingdoms
- TAK braucht
-disablecavedogverificationals Kommandozeilenargument, um die meisten gemoddeten Dateien zu laden. Ohne den Schalter weist die Engine alles ab, dessen Hash nicht auf ihrer Allowlist steht. - TAK hat in den Daten 8 Seitencodes, nicht 4: ARA / TAR / VER / ZON für die vier spielbaren Seiten, dazu CRE (Creon, Iron Plague), MON (Monster), LIF (Tierwelt), NPC (Kampagnenfiguren). Das Filtern von Einheitenlisten muss mit allen zurechtkommen.
- Die Waffen von TAK stehen inline in jeder FBI als Unterabschnitte
[WEAPON1]–[WEAPON3], nicht in einem eigenen Verzeichnisweapons/*.tdf. - Die Baumenüs von TAK sind linear, nicht 2×3. Jede Baueinheit hat ein
Verzeichnis
canbuild/<builder>/<unit>.tdfmit einem einzigen Block[Menu] { Priority = N; }.
Siehe auch
- Modding-Tutorial – Rundgang durch einen Einheiten-Mod für TA, von Anfang bis Ende.
- Glossar – Definitionen aller formatübergreifenden Begriffe, auf die oben verwiesen wird.
- Schnellstart – fünf kbot-Befehle für den Anfang.