Tutte le pagine dei formati ↓
Mappe e terreno

SCT — Sezioni di mappa

Fonte: coreprime/kbot @ 0ab97bf · Modifica su GitHub

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 .tnt finite. 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.

Sezione costiera di Greenworld disegnata come tile
sections/greenworld/coast/b_n_w02_135.sct disegnata da kbot sct image

Minimappa della sezione    Mappa delle altezze della sezione
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 == 2 ha 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 che Version ∈ {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)

Vedi anche

  • TNT: il formato di mappa assemblato che usa le sezioni.
  • PAL: la palette usata per colorare sia i pixel dei tile sia la minimappa.
  • Glossario: tile, cella degli attributi (attribute cell), mappa delle altezze (heightmap).