SCT — Sezioni di mappa
Un file
.sctè un pezzo riutilizzabile di terreno di una mappa: i level designer di Cavedog ne cucivano insieme decine nell'editor di mappe ufficiale (TAE) per costruire le mappe.tntfinite. Ogni sezione contiene la propria grafica dei tile, la griglia dei tile, le altezze per cella e una minimappa di anteprima. Le sezioni sono i mattoni; i TNT sono il prodotto assemblato.
sections/greenworld/coast/b_n_w02_135.sct disegnata da kbot sct image
Minimappa incorporata (a sinistra) e griglia delle elevazioni (a destra).
Tip
Provalo tu stesso.
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
Consulta il riferimento CLI di kbot sct.
Da Go. Usa 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))
Struttura su disco
┌─ 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
I campi puntatore possono indicare le sezioni in qualsiasi ordine, ma gli strumenti di Cavedog le scrivono nella disposizione mostrata qui sopra, ed è quella che ogni lettore di terze parti presuppone.
Intestazione (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;
| Campo | Note |
|---|---|
Version |
3 per le sezioni originali di TA. Alcuni primi prototipi usano 2: stessa struttura, ma le voci delle altezze sono di 8 byte invece che di 4. kbot accetta entrambe. |
Width, Height |
Entrambe espresse in tile (unità da 32 px). Per una sezione compatibile con TAE devono essere entrambe multiple di 4 (cioè multiple di 128 px). |
NumTiles |
Numero di tile unici. La griglia di indici nella sezione dei dati rimanda a questo array. |
Pixel dei tile
NumTiles blocchi da 32 × 32 = 1024 byte ciascuno: indici nella palette di
TA. Il formato non elimina automaticamente i tile identici, quindi una
sezione costruita male può sprecare spazio; il comando image di kbot
avvisa se una sezione ha tile irraggiungibili.
Dati della sezione — indici dei tile + griglia delle altezze
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];
La griglia delle altezze è quattro volte più fitta di quella dei tile:
ogni tile riceve 2 × 2 = 4 campioni di altezza a una risoluzione di 16
pixel, come funzionano le celle degli attributi dei TNT. I campi always_-1
e always_0 sono metadati di lavoro dell'editor; nel round-trip puoi
riscrivere l'uno o l'altro valore.
Minimappa
128 × 128 indici della palette. Le dimensioni sono fisse, qualunque siano
la larghezza e l'altezza in tile della sezione, e la minimappa viene
stirata per adattarsi alle proporzioni della sezione invece di essere
incorniciata da bande (letterbox).
Ordine di lettura
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)
Esempio svolto — 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
Una sezione di 4×4 tile è la più piccola che TAE accetti (le dimensioni
devono essere multiple di 128 px). Pur avendo la sezione 4 × 4 = 16
posizionamenti, fa riferimento a 64 tile unici, perché ogni cella 32×32 è a
sua volta delimitata da transizioni di bordo di cui il designer voleva delle
varianti. È normale: le sezioni barattano spazio su disco con libertà di
fusione.
Come i TNT usano le sezioni
Il pool di tile di una mappa .tnt è l'unione di tutti gli .sct che il
level designer vi ha "dipinto", con i duplicati eliminati a posteriori da
TAE. Quindi, quando scopri che due TNT condividono un tile, quasi sempre
viene dallo stesso SCT.
Il collegamento esiste solo in fase di costruzione. Il motore di gioco
non apre mai una sezione; vede soltanto il TNT già assemblato. Le sezioni
stanno su disco negli archivi dell'editor (worlds.hpi) e negli archivi dei
mondi della campagna, ad es. sections/greenworld/coast/,
sections/lava/hills/, ecc.
Insidie
Warning
Width × Height deve essere un multiplo di 4 perché TAE carichi la
sezione. Il formato in sé non lo impone (puoi scrivere una sezione di 3×3
tile e kbot la disegnerà senza problemi), ma l'editor di Cavedog la
rifiuterà con un criptico errore "section misaligned".
Version == 2ha celle delle altezze da 8 byte, non 4. Il primo byte è comunque l'elevazione; gli altri 7 byte sono dati di lavoro dell'editor che puoi azzerare in scrittura.- La minimappa 128×128 viene stirata, non incorniciata da bande, per adattarsi alle proporzioni della sezione. Una sezione 4×16 apparirà orribilmente schiacciata nella minimappa.
- Non c'è una firma oltre a
Version. Per validare un candidato SCT, controlla cheVersion ∈ {2, 3}e che i quattro campi puntatore cadano tutti dentro il file. - Gli intervalli di altezza dipendono interamente dal designer. TAE limita a 0–255, ma una sezione può essere perfettamente piatta (un solo valore) o coprire l'intero intervallo. Il renderer dei TNT normalizza prima di mostrare; l'SCT no.
Dimensioni tipiche
| Elemento | Intervallo osservato in sections/**/*.sct di Cavedog |
|---|---|
| Dimensione del file | 30 KB – 2 MB |
| Dimensioni della sezione (tile) | 4×4 – 32×32 |
| Tile unici per sezione | 30–600 |
| Costo dell'intestazione | sempre 28 byte |
| Minimappa (sempre 128×128 con palette) | 16384 byte |
Sezioni in worlds.hpi |
~5000 (in tutti i biomi) |