Todas as páginas de formatos ↓
Mapas e terreno

SCT — Secções de mapa

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

Um ficheiro .sct é um bloco reutilizável de terreno de mapa: os designers de níveis da Cavedog juntavam dezenas destes no editor de mapas oficial (TAE) para construir os mapas .tnt finais. Cada secção traz os seus próprios gráficos de mosaicos, a grelha de mosaicos, as alturas de cada célula e um minimapa de pré-visualização. As secções são os tijolos; os TNT são o produto montado.

Secção de costa do Greenworld renderizada em mosaicos
sections/greenworld/coast/b_n_w02_135.sct renderizado por kbot sct image

Minimapa da secção    Mapa de alturas da secção
Minimapa incorporado (à esquerda) e grelha de elevação (à direita).

Tip

Experimente por si.

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

Consulte a referência de kbot sct da linha de comandos.

A partir de 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))

Disposição 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 do ficheiro por qualquer ordem, mas as ferramentas da Cavedog escrevem-nas pela disposição mostrada acima, e é isso que todos os leitores de terceiros assumem.

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 Notas
Version 3 nas secções da versão comercial do TA. Alguns protótipos antigos usam 2: a mesma disposição, mas as entradas de altura têm 8 bytes em vez de 4. O kbot aceita ambas.
Width, Height Ambos expressos em mosaicos (unidades de 32 px). Numa secção compatível com o TAE, ambos têm de ser múltiplos de 4 (ou seja, múltiplos de 128 px).
NumTiles Número de mosaicos únicos. A grelha de índices da parte de dados refere-se a este vetor.

Píxeis dos mosaicos

NumTiles blocos de 32 × 32 = 1024 bytes cada, com índices da paleta do TA. O formato não elimina automaticamente os mosaicos idênticos, por isso uma secção mal construída pode desperdiçar espaço; o comando image do kbot avisa se uma secção tiver mosaicos inalcançáveis.

Dados da secção — índices de mosaicos + grelha 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 grelha de alturas é quatro vezes mais densa do que a grelha de mosaicos: cada mosaico recebe 2 × 2 = 4 amostras de altura com resolução de 16 píxeis, tal como funcionam as células de atributos do TNT. Os campos always_-1 e always_0 são metadados de trabalho do editor; numa ida e volta, pode voltar a escrever qualquer um dos valores.

Minimapa

128 × 128 índices da paleta. As dimensões são fixas, seja qual for a largura/altura da secção em mosaicos, e o minimapa é esticado para se ajustar à proporção da secção, em vez de levar barras (letterbox).


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 secção de 4×4 mosaicos é a mais pequena que o TAE aceita (as medidas têm de ser múltiplos de 128 px). Embora a secção tenha 4 × 4 = 16 posições, refere 64 mosaicos únicos, porque cada célula de 32×32 está ela própria delimitada por transições nas margens, das quais o designer queria variantes. Isto é normal: as secções trocam espaço de armazenamento por liberdade de mistura.


Como o TNT usa as secções

O conjunto de mosaicos de um mapa .tnt é a união de todos os .sct que o designer de níveis "pintou" nele, com os duplicados eliminados depois pelo TAE. Por isso, quando descobrir que dois TNT partilham um mosaico, é quase certo que veio do mesmo SCT.

A ligação existe apenas no momento da construção. O motor nunca abre uma secção durante o jogo; só vê o TNT já combinado. As secções ficam no disco, nos arquivos do editor (worlds.hpi) e nos arquivos dos mundos da campanha, por exemplo sections/greenworld/coast/, sections/lava/hills/, etc.


Armadilhas

Warning

Width × Height tem de ser múltiplo de 4 para o TAE carregar a secção. O formato em si não o impõe (pode escrever uma secção de 3×3 mosaicos e o kbot renderiza-a sem problemas), mas o editor da Cavedog rejeita-a com um erro críptico, "section misaligned".

  • Com Version == 2, as células de altura têm 8 bytes, e não 4. O primeiro byte continua a ser a elevação; os restantes 7 bytes são dados de trabalho do editor, que pode pôr a zero ao escrever.
  • O minimapa de 128×128 é esticado, sem barras, para se ajustar à proporção da secção. Uma secção de 4×16 fica horrivelmente achatada no minimapa.
  • Não há assinatura além de Version. Para validar um SCT candidato, verifique se Version ∈ {2, 3} e se os quatro campos de ponteiro ficam todos dentro do ficheiro.
  • Os intervalos de alturas ficam inteiramente ao critério do designer. O TAE limita-os a 0–255, mas uma secção pode ser perfeitamente plana (um único valor) ou usar o intervalo completo. O renderizador de TNT normaliza antes de mostrar; o SCT não.

Tamanhos típicos

Recurso Intervalo observado em sections/**/*.sct da Cavedog
Tamanho do ficheiro 30 KB – 2 MB
Dimensões da secção (mosaicos) 4×4 – 32×32
Mosaicos únicos por secção 30–600
Espaço ocupado pelo cabeçalho sempre 28 bytes
Minimapa (sempre 128×128, com paleta) 16384 bytes
Secções em worlds.hpi ~5000 (em todos os biomas)

Ver também

  • TNT — o formato de mapa montado, que usa as secções.
  • PAL — a paleta usada para colorir tanto os píxeis dos mosaicos como o minimapa.
  • Glossário — mosaico, célula de atributos, mapa de alturas.