Alle Formatseiten ↓
Karten und Gelände

SCT – Kartensektionen

Aus coreprime/kbot @ 0ab97bf · Auf GitHub bearbeiten

Eine .sct-Datei ist ein wiederverwendbares Stück Kartengelände – Cavedogs Leveldesigner haben im offiziellen Karteneditor (TAE) Dutzende davon zusammengefügt, um die fertigen .tnt-Karten zu bauen. Jede Sektion bündelt ihre eigenen Kachelgrafiken, ihr Kachelraster, Höhen pro Zelle und eine Minikarte als Vorschaubild. Sie sind die Bausteine; TNTs sind das zusammengesetzte Produkt.

Küstensektion aus Greenworld, als Kacheln gerendert
sections/greenworld/coast/b_n_w02_135.sct, gerendert mit kbot sct image

Minikarte der Sektion    Höhenkarte der Sektion
Eingebettete Minikarte (links) und Höhenraster (rechts).

Tip

Probier es selbst.

kbot sct info       sections/greenworld/coast/b_n_w02_135.sct
kbot sct describe   sections/greenworld/coast/b_n_w02_135.sct
kbot sct image      sections/greenworld/coast/b_n_w02_135.sct -t out.png
kbot sct minimap    sections/greenworld/coast/b_n_w02_135.sct -t mini.png
kbot sct heightmap  sections/greenworld/coast/b_n_w02_135.sct -t height.png

Siehe die kbot sct-Referenz der CLI.

Aus Go heraus. Verwende formats/sct:

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

f, _ := os.Open("sections/greenworld/coast/b_n_w02_135.sct")
defer f.Close()
s, _ := sct.LoadFromReader(f)
fmt.Printf("%dx%d tiles, %d unique, %d heights\n",
    s.Header.Width, s.Header.Height, s.Header.NumTiles, len(s.HeightMap))

Aufbau auf der Platte

┌─ Header (28 B) ──┐  version, pointers, dimensions
├─ Tile pixels ────┤  NumTiles × 1024 bytes (32×32 palette indices)
├─ Section data ───┤  Width × Height × int16 tile indices
├─ Height grid ────┤  (Width × 2) × (Height × 2) × {4 or 8} bytes
└─ Minimap ────────┘  128 × 128 palette indices

Die Zeigerfelder können in beliebiger Reihenfolge auf die Abschnitte zeigen, aber Cavedogs Werkzeuge geben sie im oben gezeigten Aufbau aus, und davon geht jeder Leser von Drittanbietern aus.

Header (28 Byte)

typedef struct {
    uint32 Version;     // 2 or 3 (TA's TAE always emits 3)
    uint32 PtrMinimap;  // → 128×128 minimap
    uint32 NumTiles;    // unique 32×32 tile count
    uint32 PtrTiles;    // → tile pixel block
    uint32 Width;       // section width in tiles
    uint32 Height;      // section height in tiles
    uint32 PtrData;     // → tile-index grid + heights
} SCTHeader;
Feld Anmerkungen
Version 3 bei Sektionen der Verkaufsversion von TA. Einige frühe Prototypen verwenden 2 – gleicher Aufbau, aber Höheneinträge zu 8 statt 4 Byte. kbot akzeptiert beides.
Width, Height Beide in Kacheln angegeben (Einheiten zu 32 px). Für eine Sektion, die TAE verarbeiten kann, müssen beide Vielfache von 4 sein (also Vielfache von 128 px).
NumTiles Anzahl der einzigartigen Kacheln. Das Indexraster im Datenabschnitt verweist in dieses Array.

Kachelpixel

NumTiles Blöcke zu je 32 × 32 = 1024 Byte – Palettenindizes in die Palette von TA. Identische Kacheln werden vom Format nicht automatisch zusammengefasst, eine schlecht gebaute Sektion kann also Platz verschwenden; der Befehl image von kbot warnt, wenn eine Sektion unerreichbare Kacheln hat.

Sektionsdaten – Kachelindizes + Höhenraster

int16 tileMap[Height][Width];     // Index into the tile pixel array
                                  // (signed; negative values are unused
                                  // in retail content but valid)

struct HeightCell_V3 { uint8 h; int16 always_minus_one; uint8 always_zero; };
struct HeightCell_V2 { uint8 h; int16 always_minus_one; uint8 always_zero;
                       uint32 reserved; };

HeightCell heights[Height * 2][Width * 2];

Das Höhenraster ist viermal so dicht wie das Kachelraster – jede Kachel bekommt 2 × 2 = 4 Höhenwerte in einer Auflösung von 16 Pixeln, passend zur Funktionsweise der Attributzellen von TNT. Die Felder always_-1 und always_0 sind Hilfsmetadaten aus dem Editor; du kannst beim Round-Trip jeden der beiden Werte zurückschreiben.

Minikarte

128 × 128 Palettenindizes. Die Maße sind unabhängig von Breite und Höhe der Sektion in Kacheln fest, und die Minikarte wird auf das Seitenverhältnis der Sektion gestreckt, statt mit Balken eingepasst zu werden.


Lesereihenfolge

header = read_struct(SCTHeader)
assert header.Version in (2, 3)

seek(header.PtrTiles)
tiles = [read(1024) for _ in range(header.NumTiles)]

seek(header.PtrData)
tile_map = read_int16_array(header.Width * header.Height)

entry_size = 4 if header.Version == 3 else 8
attrs_w, attrs_h = header.Width * 2, header.Height * 2
heights = [read(entry_size)[0] for _ in range(attrs_w * attrs_h)]

seek(header.PtrMinimap)
minimap = read(128 * 128)

Beispiel im Detail – b_n_w02_135.sct

$ kbot sct describe sections/greenworld/coast/b_n_w02_135.sct
Version:    3
Section:    4 × 4 tiles  (128 × 128 px)
Tiles:      64 unique
Heights:    8 × 8 cells (height range 50–62)
Minimap:    128 × 128

Eine Sektion aus 4×4 Kacheln ist die kleinste, die TAE akzeptiert (es müssen Vielfache von 128 px sein). Obwohl die Sektion 4 × 4 = 16 Platzierungen hat, verweist sie auf 64 einzigartige Kacheln, weil jede 32×32-Zelle selbst von Randübergängen begrenzt ist, für die der Designer Varianten haben wollte. Das ist normal – Sektionen tauschen Speicherplatz gegen Freiheit beim Überblenden.


Wie TNT Sektionen verwendet

Der Kachelvorrat einer .tnt-Karte ist die Vereinigung aller .sct, die der Leveldesigner hineingemalt hat, nachträglich von TAE von Duplikaten befreit. Wenn sich also zwei TNTs eine Kachel teilen, stammt sie fast immer aus derselben SCT.

Die Verbindung besteht nur zur Bauzeit. Die Engine öffnet zur Laufzeit nie eine Sektion; sie sieht nur die bereits zusammengesetzte TNT. Sektionen liegen auf der Platte in den Editor-Archiven (worlds.hpi) und den Weltarchiven der Kampagne, z. B. sections/greenworld/coast/, sections/lava/hills/ usw.


Stolperfallen

Warning

Width × Height muss ein Vielfaches von 4 sein, damit TAE die Sektion lädt. Das Format selbst erzwingt das nicht – du kannst eine Sektion aus 3×3 Kacheln schreiben, und kbot rendert sie anstandslos –, aber Cavedogs Editor lehnt sie mit einem kryptischen Fehler „section misaligned“ ab.

  • Version == 2 hat Höhenzellen zu 8 Byte, nicht zu 4. Das erste Byte ist nach wie vor die Höhe; die übrigen 7 Byte sind Hilfsdaten des Editors, die du beim Schreiben nullen kannst.
  • Die Minikarte von 128×128 wird gestreckt, nicht mit Balken eingepasst, um auf das Seitenverhältnis der Sektion zu passen. Eine Sektion von 4×16 sieht in der Minikarte furchtbar gestaucht aus.
  • Außer Version gibt es keine Signatur. Um eine mutmaßliche SCT zu prüfen, stelle sicher, dass Version ∈ {2, 3} gilt und alle vier Zeigerfelder innerhalb der Datei liegen.
  • Die Höhenbereiche liegen ganz beim Designer. TAE begrenzt auf 0–255, aber eine Sektion kann vollkommen flach sein (ein einziger Wert) oder den vollen Bereich nutzen. Der TNT-Renderer normalisiert vor der Anzeige; die SCT tut das nicht.

Typische Größen

Asset Beobachteter Bereich in Cavedogs sections/**/*.sct
Dateigröße 30 KB – 2 MB
Sektionsmaße (Kacheln) 4×4 – 32×32
Einzigartige Kacheln pro Sektion 30–600
Header-Overhead immer 28 Byte
Minikarte (immer 128×128 mit Palette) 16.384 Byte
Sektionen in worlds.hpi ~5.000 (über alle Biome)

Siehe auch

  • TNT – das zusammengesetzte Kartenformat, das Sektionen verarbeitet.
  • PAL – die Palette, mit der Kachelpixel und Minikarte eingefärbt werden.
  • Glossar – tile, attribute cell, heightmap.