Todas as páginas de formatos ↓
Mapas e terreno

SCT: seções de mapa

Fonte: coreprime/kbot @ 0ab97bf · Editar no GitHub

Um arquivo .sct é um pedaço reutilizável de terreno de mapa: os designers de fases da Cavedog juntavam dezenas deles no editor de mapas oficial (TAE) para montar os mapas .tnt finais. Cada seção reúne os seus próprios gráficos de blocos, a grade de blocos, as alturas por célula e um minimapa em miniatura. As seções são os blocos de montagem; os TNTs são o produto montado.

Seção de litoral do Greenworld renderizada como blocos
sections/greenworld/coast/b_n_w02_135.sct renderizado por kbot sct image

Minimapa da seção    Mapa de altura da seção
Minimapa embutido (à esquerda) e grade de elevação (à direita).

Tip

Experimente você mesmo.

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

Veja a referência do kbot sct da linha de comando.

Em Go. Use 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))

Estrutura no 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

Os campos de ponteiro podem apontar para as partes em qualquer ordem, mas as ferramentas da Cavedog as gravam na estrutura mostrada acima, e é isso que todo leitor de terceiros pressupõe.

Cabeçalho (28 bytes)

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 Observações
Version 3 nas seções da versão comercial do TA. Alguns protótipos antigos usam 2: a mesma estrutura, mas com entradas de altura de 8 bytes em vez de 4. O kbot aceita as duas.
Width, Height Os dois medidos em blocos (unidades de 32 px). Numa seção compatível com o TAE, os dois precisam ser múltiplos de 4 (ou seja, múltiplos de 128 px).
NumTiles Número de blocos únicos. A grade de índices da parte de dados aponta para esse array.

Pixels dos blocos

NumTiles blocos de 32 × 32 = 1024 bytes cada: índices na paleta do TA. Blocos idênticos não são eliminados automaticamente pelo formato, por isso uma seção mal montada pode desperdiçar espaço. O comando image do kbot avisa quando uma seção tem blocos inalcançáveis.

Dados da seção: índices de blocos + grade de alturas

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];

A grade de alturas é quatro vezes mais densa que a grade de blocos: cada bloco recebe 2 × 2 = 4 amostras de altura com resolução de 16 pixels, como as células de atributo do TNT. Os campos always_-1 e always_0 são metadados de rascunho do editor. Na ida e volta, qualquer valor pode ser regravado.

Minimapa

128 × 128 índices da paleta. As dimensões são fixas, qualquer que seja a largura ou a altura da seção em blocos, e o minimapa é esticado para caber na proporção da seção, em vez de ganhar faixas nas bordas.


Ordem de leitura

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)

Exemplo comentado: 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

Uma seção de 4×4 blocos é a menor que o TAE aceita (as dimensões precisam ser múltiplas de 128 px). Embora a seção tenha 4 × 4 = 16 posições, ela referencia 64 blocos únicos, porque cada célula de 32×32 é delimitada por transições de borda das quais o designer quis ter variações. Isso é normal: as seções trocam espaço de armazenamento por liberdade de mesclagem.


Como o TNT usa as seções

O conjunto de blocos de um mapa .tnt é a união de todos os .sct que o designer de fases "pintou" nele, com as duplicatas eliminadas depois pelo TAE. Por isso, quando dois TNTs têm um bloco em comum, ele quase sempre veio do mesmo SCT.

A ligação existe só na hora de montar o mapa. O motor do jogo nunca abre uma seção: ele só vê o TNT já montado. As seções ficam no disco, nos arquivos compactados do editor (worlds.hpi) e nos arquivos compactados dos mundos da campanha, por exemplo sections/greenworld/coast/, sections/lava/hills/ etc.


Armadilhas

Warning

Width × Height precisa ser múltiplo de 4 para o TAE carregar a seção. O formato em si não exige isso (dá para gravar uma seção de 3×3 blocos, e o kbot a renderiza sem problema), mas o editor da Cavedog a rejeita com um erro enigmático, "section misaligned".

  • Version == 2 tem células de altura de 8 bytes, não de 4. O primeiro byte continua sendo a elevação. Os 7 bytes restantes são rascunho do editor, que podem ser zerados na gravação.
  • O minimapa de 128×128 é esticado, e não ganha faixas nas bordas, para caber na proporção da seção. Uma seção de 4×16 fica horrivelmente achatada no minimapa.
  • Não há assinatura além de Version. Para validar um candidato a SCT, confira se Version ∈ {2, 3} e se os quatro campos de ponteiro caem todos dentro do arquivo.
  • As faixas de altura ficam inteiramente a critério do designer. O TAE limita a 0–255, mas uma seção pode ser totalmente plana (um único valor) ou usar a faixa inteira. O renderizador do TNT normaliza antes de exibir; o SCT, não.

Tamanhos típicos

Recurso Faixa observada em sections/**/*.sct da Cavedog
Tamanho do arquivo 30 KB – 2 MB
Dimensões da seção (blocos) 4×4 – 32×32
Blocos únicos por seção 30–600
Custo do cabeçalho sempre 28 bytes
Minimapa (sempre 128×128 com paleta) 16.384 bytes
Seções em worlds.hpi ~5.000 (em todos os biomas)

Veja também

  • TNT: o formato de mapa montado que usa as seções.
  • PAL: a paleta usada para colorir os pixels dos blocos e o minimapa.
  • Glossário: tile (bloco), attribute cell (célula de atributo), heightmap (mapa de altura).