Formatos de Arquivo do Outpost 2 · bei.pm
Os formatos de arquivo descritos nesta página são baseados na análise técnica da propriedade intelectual de Dynamix, Inc. e Sierra Entertainment.
A propriedade intelectual faz parte da massa da Activision Publishing, Inc. / Activision Blizzard, Inc. e atualmente é de propriedade da Microsoft Corp..
As informações foram coletadas através de Engenharia Reversa e Análise de Dados para fins de arquivamento e interoperabilidade com dados históricos.
Nenhuma especificação proprietária ou confidencial foi utilizada.
O jogo pode ser adquirido atualmente como download em gog.com.
A seguinte série de artigos documenta minhas descobertas sobre os formatos de dados no jogo de estratégia em tempo real "Outpost 2: Divided Destiny", que foi lançado em 1997 pela Sierra e desenvolvido pela Dynamix.
Eu me dediquei, aproximadamente, de 01 de novembro de 2015 até 14 de novembro de 2015, principalmente à análise dos dados do jogo - e o que pode ser feito com eles.
De acordo com as informações que consegui até agora, a Dynamix - assim como muitas empresas comerciais - não desenvolveu alguns formatos de dados especificamente para Outpost 2, mas os utilizou em outros desenvolvimentos, como por exemplo na série Mechwarrior (modificados).
Independentemente disso, também é possível observar que a capacidade de inovação dos formatos de dados é praticamente limitada e frequentemente se baseia em conceitos mais antigos de formatos comuns como JFIF e RIFF.
Para a interpretação das tabelas e formatos de dados, há mais informações disponíveis em O que é o que?.
Os dados aqui apresentados devem ser compreendidos, em geral, como Little Endian.
Por fim, pode-se dizer que a engenharia reversa foi muito divertida, mesmo que não esteja completa.
Naturalmente, eu também recomendo jogar o próprio jogo, pois ele oferece mecânicas de jogo interessantes.
Introdução
Os formatos de dados usados pelo Outpost 2 têm uma estrutura semelhante à do JFIF / PNG - os blocos de dados individuais sempre possuem um cabeçalho de 8 bytes. Portanto, não vou me dar ao trabalho de documentar os cabeçalhos individuais nos locais específicos correspondentes e apenas documentarei as divergências.
O formato é sempre o seguinte; os dados úteis reais estão então incorporados nele:
Endereço | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | caractere | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . |
Deslocamento | Tipo de dado | Designação | Explicação |
---|---|---|---|
0x0000 | uint(32) | Bytes Mágicos | Contém informações sobre o que esperar no próximo bloco de dados. Valores conhecidos:
|
0x0004 | uint(24) | Comprimento do bloco | Contém a informação sobre o tamanho (em bytes) do seguinte bloco de dados. Neste caso, refere-se apenas aos dados úteis - os 8 bytes do cabeçalho não estão incluídos. |
0x0007 | uint(8) | Bandeiras? | É desconhecido para que serve exatamente este bloco. Nos volumes, este valor é frequentemente 0x80, enquanto em outros arquivos é frequentemente 0x00. Isso sugere que se trata de um conjunto de flags. |
Volumes
Os volumes são um contêiner de dados para o jogo, semelhante a um formato de arquivo como, por exemplo, Tarball. Pelo menos em Outpost 2, o formato reconhece apenas arquivos - sem pastas. Provavelmente, essas poderiam ser simuladas por meio de nomes de arquivos apropriados.
Um volume consiste no cabeçalho do volume e em vários blocos de volume, que correspondem aos arquivos concretos.
"Volumes" são os arquivos com a extensão 'vol'
no diretório do jogo.
Endereço | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | caractere | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | 56 | 4f | 4c | 20 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | V | O | L | . | . | . | . | . | . | . | . | . | . | . | . |
Deslocamento | Tipo de dado | Designação | Explicação |
---|---|---|---|
0x0000 | uint(32) | Bytes Mágicos | |
0x0004 | uint(24) | Comprimento do bloco | |
0x0007 | uint(8) | Bandeiras |
Cabeçalho de Volume
Endereço | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | caractere | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | 76 | 6f | 6c | 68 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | v | o | l | h | . | . | . | . | . | . | . | . | . | . | . | . |
Deslocamento | Tipo de dado | Designação | Explicação |
---|---|---|---|
0x0000 | uint(32) | Bytes Mágicos | |
0x0004 | uint(24) | Comprimento do bloco | |
0x0007 | uint(8) | Bandeiras |
O cabeçalho do volume não contém dados úteis.
Ele serve apenas como um contêiner.
Como primeira informação no cabeçalho do volume, devem estar as strings do volume; em seguida, vêm as informações do volume.
Strings de Volume
Endereço | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | caractere | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | 76 | 6f | 6c | 69 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | v | o | l | i | . | . | . | . | . | . | . | . | . | . | . | . |
Deslocamento | Tipo de dado | Designação | Explicação |
---|---|---|---|
0x0000 | uint(32) | Bytes Mágicos | |
0x0004 | uint(24) | Comprimento do bloco | |
0x0007 | uint(8) | Bandeiras |
Endereço | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | caractere | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | 76 | 6f | 6c | 73 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | v | o | l | s | . | . | . | . | . | . | . | . | . | . | . | . |
Deslocamento | Tipo de dado | Designação | Explicação |
---|---|---|---|
0x0000 | uint(32) | Bytes Mágicos | |
0x0004 | uint(24) | Comprimento do bloco | |
0x0007 | uint(8) | Bandeiras | |
0x0008 | uint(32) | Comprimento do payload | Indica quantos bytes dos dados seguintes são realmente dados úteis. Os dados restantes da lista de Volume-Strings parecem ser classificados como lixo. Em arquivos com data posterior, esses 'dados restantes' são 0x00, o que pode indicar deficiências na ferramenta durante o desenvolvimento do jogo, ou seja, que um desenvolvedor só se preocupou com a correta inicialização dos buffers muito tarde, uma vez que não afeta o jogo se os dados estão inicializados ou não. |
0x000c | uint(8)[] | Lista de nomes de arquivos | Trata-se de uma lista de nomes de arquivos terminada em 0 bytes, que - pelo menos no componente de dados presente - parece esperar apenas caracteres ASCII. Não é necessário analisar esse bloco de dados com mais detalhes ao fazer o parsing, uma vez que nas informações do volume os offsets dos nomes dos arquivos são referenciados diretamente. |
Os Volume Strings são uma lista de nomes de arquivos que estão contidos dentro do volume.
Informações de Volume
Endereço | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | caractere | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | 76 | 6f | 6c | 69 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | v | o | l | i | . | . | . | . | . | . | . | . | . | . | . | . |
Deslocamento | Tipo de dado | Designação | Explicação |
---|---|---|---|
0x0000 | uint(32) | Bytes Mágicos | |
0x0004 | uint(24) | Comprimento do bloco | |
0x0007 | uint(8) | Bandeiras |
As informações de volume contêm detalhes adicionais sobre os arquivos. De certa forma, isso é uma espécie de entrada de diretório FAT (FAT = Tabela de Alocação de Arquivos).
O número de arquivos é determinado pelo tamanho do bloco dividido pelo comprimento das entradas de diretório - 14 bytes.
Cada uma das entradas de diretório tem a seguinte estrutura:
Endereço | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | caractere | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . |
Deslocamento | Tipo de dado | Designação | Explicação |
---|---|---|---|
0x0000 | uint(32) | Deslocamento do nome do arquivo | Indica em qual offset (!) dentro da lista de nomes de arquivos (Strings de Volume) o nome do arquivo é encontrado. Refere-se ao início do bloco de dados úteis. |
0x0004 | uint(32) | Deslocamento do arquivo | Indica em qual offset dentro do arquivo de volume total a arquivo se encontra. |
0x0008 | uint(32) | Tamanho do arquivo | Indica o tamanho do arquivo em bytes. |
0x000c | uint(16) | Bandeiras? | Parece haver informações adicionais sobre a codificação do arquivo.
|
Bloco de Volume
Endereço | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | caractere | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | 56 | 42 | 4c | 48 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | V | B | L | H | . | . | . | . | . | . | . | . | . | . | . | . |
Deslocamento | Tipo de dado | Designação | Explicação |
---|---|---|---|
0x0000 | uint(32) | Bytes Mágicos | |
0x0004 | uint(24) | Comprimento do bloco | |
0x0007 | uint(8) | Bandeiras |
Um bloco de volume é um contêiner que armazena arquivos. Ele contém apenas mais uma vez - devido ao formato do bloco - a redundância do tamanho do arquivo e, em seguida, seguem-se diretamente os dados úteis.
Azulejos
Endereço | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | caractere | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | 50 | 42 | 4d | 50 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | P | B | M | P | . | . | . | . | . | . | . | . | . | . | . | . |
Deslocamento | Tipo de dado | Designação | Explicação |
---|---|---|---|
0x0000 | uint(32) | Bytes Mágicos | |
0x0004 | uint(24) | Comprimento do bloco | |
0x0007 | uint(8) | Bandeiras |
Os Tiles são um formato de gráfico bitmap específico do Outpost-2. Eles se estendem por 13 conjuntos de tiles, chamados de "wells" (well0000.bmp
até well0012.bmp
), que estão dentro do volume maps.vol.
Os conjuntos de tiles / wells contêm o seguinte:
Nome do arquivo | Conteúdo |
---|---|
well0000.bmp | Uma imagem azul de 32x32px - ideal para testar se o carregador de imagens está funcionando |
well0001.bmp | Contém rochas claras, cadeias de montanhas sobre rochas claras e inúmeras variantes de crateras de impacto em rochas claras |
well0002.bmp | Contém 'Doodads' de rochas claras - ou seja, elementos que podem ser colocados para decorar (ou intencionalmente como estrutura, como muros) em rochas claras, incluindo vegetação |
well0003.bmp | Contém uma estrutura semelhante a crosta em rochas claras |
well0004.bmp | Contém rochas escuras, cadeias de montanhas sobre rochas escuras e inúmeras variantes de crateras de impacto em rochas escuras |
well0005.bmp | Contém 'Doodads' de rochas escuras - ou seja, elementos que podem ser colocados para decorar (ou intencionalmente como estrutura, como muros) em rochas escuras |
well0006.bmp | Contém uma estrutura semelhante a crosta em rochas escuras, assim como transições entre rochas claras e escuras |
well0007.bmp | Contém lava, incluindo 4-5 quadros de animação da mesma |
well0008.bmp | Contém areia e inúmeras variantes de crateras de impacto em areia |
well0009.bmp | Contém 'Doodads' de areia - ou seja, elementos que podem ser colocados para decorar (ou intencionalmente como estrutura, como muros) em areia |
well0010.bmp | Contém 48 transições de areia para rochas claras e escuras |
well0011.bmp | Contém as calotas polares do mapa, com rochas escuras como fundo |
well0012.bmp | Contém as calotas polares do mapa, com rochas claras como fundo |
É altamente recomendável, para uma implementação precisa, não renderizar os tiles antecipadamente para que possam ser armazenados em cache, pois os dados para o ciclo dia/noite ainda precisam ser processados - e haveria uma quantidade muito grande de dados.
Os tiles são gráficos 8bpp com paleta indexada, cada um com resolução de 32x32 pixels, dispostos entre si. Em um tileset assim formado, no entanto, pode haver muito mais.
O contêiner principal é composto por 2 seções: head
e data
.
Cabeçalho dos Azulejos
Endereço | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | caractere | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | 68 | 65 | 61 | 64 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | h | e | a | d | . | . | . | . | . | . | . | . | . | . | . | . |
0x0010 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . |
Deslocamento | Tipo de dado | Designação | Explicação |
---|---|---|---|
0x0000 | uint(32) | Bytes Mágicos | |
0x0004 | uint(24) | Comprimento do bloco | |
0x0007 | uint(8) | Bandeiras | |
0x0008 | uint(32) | Versão / Bandeiras? | Isso pode ser uma indicação de versão do formato de arquivo; em todos os arquivos que possuo, o valor aqui era |
0x000c | uint(32) | Largura (Resolução Horizontal) | Indica a largura do arquivo de imagem (em pixels). Para todos os poços do Outpost 2, o valor esperado aqui será |
0x0010 | uint(32) | Altura (Resolução Vertical) | Indica quão alta é a imagem (em pixels). Em todos os poços do Outpost 2, o valor esperado aqui será |
0x0014 | uint(32) | Profundidade de cor? | A importância deste valor é desconhecida. Uma vez que ele contém o valor |
0x0018 | uint(32) | Profundidade de cor 2? | O significado deste valor é desconhecido. Possivelmente se trata de uma profundidade de cor 'destino'. |
Após essas informações, haverá ainda um arquivo de paleta disponível no formato RIFF padronizado. A especificação exata pode ser encontrada - uma vez que as paletas também aparecem em outros lugares - em Paletas.
Dados dos Azulejos
Endereço | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | caractere | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | 64 | 61 | 74 | 61 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | d | a | t | a | . | . | . | . | . | . | . | . | . | . | . | . |
Deslocamento | Tipo de dado | Designação | Explicação |
---|---|---|---|
0x0000 | uint(32) | Bytes Mágicos | |
0x0004 | uint(24) | Comprimento do bloco | |
0x0007 | uint(8) | Bandeiras |
Finalmente, seguem os dados de pixel brutos, da esquerda para cima, linha por linha, até a parte inferior direita.
O valor dos dados nas gráficos, que geralmente estão na forma de bitmaps 8bpp, corresponde ao índice da cor na paleta de cores.
A engine de jogo provavelmente desenha os tiles *sob demanda*.
Isso parece ser devido ao ciclo dia-noite, que conhece 32 graduações de tiles individuais. Aparentemente, o valor de luminosidade é diminuído 'um pouco' a cada vez. Valores exatos ainda não foram determinados, estou trabalhando com a base de cálculo
v *= (daylight / 48) + 0.25;
usando os dados HSV dos pixels, onde daylight é um valor de 0-31 e v é um valor entre 0-1. Além disso, é importante considerar que no mapa ainda existem bordas de 16 tiles à esquerda e à direita (que servem para o aparecimento invisível de unidades).
Além disso, o ciclo dia-noite parece atualizar apenas uma coluna do mapa a cada ciclo de jogo.
Um ciclo dia-noite acelerado se parece com o seguinte:
PRT
Endereço | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | caractere | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | 43 | 50 | 41 | 4c | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | C | P | A | L | . | . | . | . | . | . | . | . | . | . | . | . |
Deslocamento | Tipo de dado | Designação | Explicação |
---|---|---|---|
0x0000 | uint(32) | Bytes Mágicos | |
0x0004 | uint(24) | Comprimento da palete | Diferente do formato de bloco normal, indica o número de paletes que podem ser encontrados neste arquivo - não o comprimento do bloco em bytes. |
0x0007 | uint(8) | Bandeiras | Provavelmente, como de costume, flags. No entanto, não conheço nenhuma flag; como todos os valores que conheço correspondem a |
Não sei exatamente o que significa PRT
; uma possibilidade poderia ser 'Tabela de Paletas e Recursos' - já que este arquivo - encontrado como op2_art.prt no maps.vol - é realmente uma tabela desse tipo, ou isso descreveria bem a sua função.
Este arquivo contém uma lista de paletas, uma tabela de todos os bitmaps utilizados, todas as definições de animação e uma série de dados desconhecidos. Ele segue de forma solta o formato de contêiner anterior, pois nem todos os registros seguem esse esquema.
A seção CPAL
(provavelmente significa Contêiner de Paletas) envolve apenas os dados das paletas, indicando quantas das paletas de 8 bits, que geralmente têm 1052 bytes, estão presentes.
A especificação de 1052 bytes não é considerada obrigatória, pois o formato da paleta pode potencialmente prever tamanhos de paletas diferentes. Ela se aplica apenas ao conjunto de dados com o qual o Outpost 2 é fornecido.
Após as listas de paletas, segue imediatamente e sem um cabeçalho introdutório, a lista de bitmaps; e logo após, as listas de animação.
Ambas são iniciadas com um uint(32) (ou novamente uint24+uint8 flags?) que contém a quantidade de registros.
Paletas
Endereço | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | caractere | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | 50 | 50 | 41 | 4c | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | P | P | A | L | . | . | . | . | . | . | . | . | . | . | . | . |
Deslocamento | Tipo de dado | Designação | Explicação |
---|---|---|---|
0x0000 | uint(32) | Bytes Mágicos | |
0x0004 | uint(24) | Comprimento da palete | Indica, ao contrário do formato de bloco normal, a quantidade de paletes encontradas neste arquivo - não o tamanho do bloco em bytes. |
0x0007 | uint(8) | Bandeiras | Provavelmente, como de costume, bandeiras. No entanto, não conheço bandeiras; como todos os valores que conheço correspondem a |
As informações das paletes são muito fáceis de ler.
Elas consistem em um cabeçalho e um segmento de dados.
Cabeçalho de Paletes
Endereço | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | caractere | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | 68 | 65 | 61 | 64 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | h | e | a | d | . | . | . | . | . | . | . | . | . | . | . | . |
Deslocamento | Tipo de dado | Designação | Explicação |
---|---|---|---|
0x0000 | uint(32) | Bytes Mágicos | |
0x0004 | uint(24) | Comprimento da palete | Indica, ao contrário do formato de bloco normal, a quantidade de paletes encontradas neste arquivo - não o tamanho do bloco em bytes. |
0x0007 | uint(8) | Bandeiras | Provavelmente, como de costume, bandeiras. No entanto, não conheço bandeiras; como todos os valores que conheço correspondem a |
0x0008 | uint(32) | Versão do formato de palete? | Define provavelmente qual versão do formato de palete a palete segue. Todos os paletes do Outpost2 parecem ter a versão |
Dados das Paletes
Endereço | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | caractere | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | 64 | 61 | 74 | 61 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | d | a | t | a | . | . | . | . | . | . | . | . | . | . | . | . |
Deslocamento | Tipo de dado | Designação | Explicação |
---|---|---|---|
0x0000 | uint(32) | Bytes Mágicos | |
0x0004 | uint(24) | Comprimento do bloco | |
0x0007 | uint(8) | Bandeiras |
A seção de dados contém as entradas individuais das paletes. A quantidade de entradas de paletes é determinada pelo comprimento do bloco / 4.
As entradas individuais têm a seguinte estrutura simples;
Endereço | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | caractere | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | -- | -- | -- | 04 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . |
Deslocamento | Tipo de dado | Designação | Explicação |
---|---|---|---|
0x0000 | uint(8) | Componente Vermelho | Indica a porcentagem de vermelho da cor |
0x0001 | uint(8) | Componente Verde | Indica a proporção de verde na cor |
0x0002 | uint(8) | Componente azul | Indica a proporção de azul na cor |
0x0003 | uint(8) | Desconhecido - Bandeiras? | Não está claro o que esse valor significa, uma vez que ele parece ser basicamente |
Quanto às paletas, só resta dizer que para as paletas a serem usadas em animações, as seguintes regras se aplicam:
- A primeira cor é SEMPRE transparente, não importa qual valor esteja indicado.
-
As entradas da paleta 1-24 são consideradas como cores do jogador nas paletas 1-8.
Não está claro de onde vêm as cores além do jogador 1.
Suspeito que as outras cores sejam hardcoded.
Mapas de bits
Endereço | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | caractere | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . |
0x0010 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . |
Deslocamento | Tipo de dado | Designação | Explicação |
---|---|---|---|
0x0000 | uint(32) | Largura alinhada | Indica a largura das linhas de dados em pixels em bytes - uma vez que estão alinhadas aos limites de 4 bytes. Dessa forma, é possível acessar rapidamente uma linha de imagem específica. Por que esse valor é armazenado separadamente, embora possa ser calculado, não está claro. |
0x0004 | uint(32) | Deslocamento | Indica o deslocamento da primeira linha no bitmap |
0x0008 | uint(32) | Altura | Indica a altura da imagem em pixels |
0x000c | uint(32) | Largura | Indica a largura da imagem em pixels |
0x0010 | uint(16) | Tipo | Indica o tipo da imagem. Aqui parece tratar-se de uma máscara de bits:
|
0x0012 | uint(16) | Paleta | Define qual palete da arquivo PRT deve ser utilizada |
Estrutura de dados do arquivo PRT indica como os bitmaps usados para os sprites são organizados. Esses bitmaps servem como um único componente, dos quais vários são montados em um quadro de animação de um sprite.
Os dados de imagem concretos estão, por outro lado, no
op2_art.BMP no diretório do jogo.
Por que esse arquivo bitmap possui um cabeçalho RIFF (predominantemente correto) não está claro. Provavelmente, o Outpost 2 usa APIs do sistema para carregar os gráficos, adotando temporariamente esse cabeçalho e sobrescrevendo os campos correspondentes e variáveis.
Os dados de pixel estão localizados no arquivo BMP na posição Offset + o uint32-Offset, encontrado no arquivo BMP no endereço 0x000A (offset de dados RIFF-Bitmap), e correspondem novamente à disposição linha a linha de cima para baixo, da esquerda para a direita.
Gráficos monocromáticos 1bpp podem ser desenhados de forma que a cor 0 represente transparência total, enquanto a cor 1 seja um preto/cinza semitransparente, já que os gráficos monocromáticos são geralmente usados para sombras de veículos e edifícios nas animações.
Dessa forma, já é possível montar muitas graficias.
Animações
Agora chegamos à classe principal das disciplinas dentro dos formatos de dados do Outpost 2:
As animações.
As listas de animação começam com um cabeçalho global, que serve principalmente para a verificação de dados. Em seguida, seguem as definições concretas de animação, que se dividem em 3 níveis:
-
Animação
Uma animação é a instância superior; ela representa uma animação de uma unidade, de um edifício ou de uma 'animação de partículas' (impacto de cometas, clima, explosão) em uma determinada situação inicial. -
Quadro
Um quadro é uma única imagem dentro de uma animação. Uma animação pode conter um ou mais quadros. -
Subquadro
Um subquadro é a informação de que uma determinada bitmap deve ser desenhada em uma determinada posição de um quadro sob certos critérios. Um quadro pode conter um ou mais subquadros.
Em seguida, já seguem as definições individuais de animação.
Endereço | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | caractere | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . |
Deslocamento | Tipo de dado | Designação | Explicação |
---|---|---|---|
0x0000 | uint(32) | Número de animações | Quantos registros de animação existem |
0x0004 | uint(32) | Número de quadros | Quantos frames deveriam estar presentes no total |
0x0008 | uint(32) | Número de Subquadros | Quantos subquadros devem estar presentes no total |
0x000c | uint(32) | Número de entradas opcionais | Quantas "entradas opcionais" estão disponíveis. |
Animação
Endereço | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | caractere | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . |
0x0010 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . |
0x0020 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . |
Deslocamento | Tipo de dado | Designação | Explicação |
---|---|---|---|
0x0000 | uint(32) | Desconhecido 1 | Informações desconhecidas |
0x0004 | uint(32) | Caixa de Limite: Esquerda | Define a posição inicial à esquerda (em pixels) da Bounding Box. |
0x0008 | uint(32) | Bounding Box: Cima | Indica o início superior (em pixels) da Bounding Box. |
0x000c | uint(32) | Caixa de Limite: Largura | Indica a largura (em pixels) da Bounding Box. |
0x0010 | uint(32) | Caixa delimitadora: altura | Indica a altura (em pixels) da Bounding Box. |
0x0014 | uint(32) | Deslocamento: X | Indica o ponto central horizontal da animação |
0x0018 | uint(32) | Deslocamento: Y | Indica o ponto médio vertical da animação |
0x001c | uint(32) | Desconhecido 2 | Informação desconhecida |
0x0020 | uint(32) | Número de quadros | Indica quantos frames de animação estão contidos nesta animação |
0x0024 | uint(32) | Número de janelas | Indica quantas janelas devem ser usadas ao desenhar |
Os dados da camada superior, da animação, são prioritariamente dados administrativos - a Boundingbox refere-se às coordenadas da marcação em torno do veículo/edifício, quando este está selecionado e também indica qual área deve ser clicável.
O offset determina prioritariamente o "ponto zero"; o ponto que deve ser adicionado ou subtraído às coordenadas internas do jogo. Poderíamos dizer de forma mais matemática: o offset aqui indica a origem das coordenadas.
As janelas (Windows) são, assim como o offset, compostas por 4 valores uint(32) cada, que indicam uma área que é considerada utilizável para subquadros individuais. Fora das janelas, desde que seja apropriado para o bitmap, não se deve desenhar.
Estrutura
Endereço | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | caractere | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . |
Deslocamento | Tipo de dado | Designação | Explicação |
---|---|---|---|
0x0000 | uint(8) | Número de subquadros e alternância para Opcional 1, 2 | Este valor contém:
|
0x0001 | uint(8) | Desconhecido 1 e Alternar para Opcional 3, 4 | Este valor contém:
|
0x0002 | uint(8) | Opcional 1 | Desconhecido |
0x0003 | uint(8) | Opcional 2 | Desconhecido |
0x0004 | uint(8) | Opcional 3 | Desconhecido |
0x0005 | uint(8) | Opcional 4 | Desconhecido |
Subquadro
Endereço | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | caractere | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . |
Deslocamento | Tipo de dado | Designação | Explicação |
---|---|---|---|
0x0000 | uint(16) | Bitmap-ID | Indica qual bitmap deve ser usada para este subquadro |
0x0002 | uint(8) | Desconhecido 1 | É desconhecido - no entanto, suspeito fortemente que se trate de uma prioridade de renderização (Z-Layer). |
0x0003 | uint(8) | Id do Subquadro | Indica em qual subquadro estamos |
0x0004 | sint(16) | Deslocamento - Horizontal | Indica onde dentro do quadro o subquadro deve ser colocado, ou quantos pixels a bitmap deve ser deslocada horizontalmente |
0x0006 | sint(16) | Offset - Vertical | Indica onde dentro do frame o subframe deve ser colocado, ou quantos pixels a bitmap deve ser deslocada verticalmente |
Com isso, agora podemos montar frames individuais, bem como animações completas, demonstrado aqui como exemplo em uma animação mais complexa, a animação com o índice 500.
Animação 500
A animação 500 mostra como um transporte Plymouth, carregado com minério comum, é descarregado. Esta é uma das poucas animações que utiliza a funcionalidade de janelas.
E assim, a animação completa pode ser montada.
Infelizmente, ainda há um problema com a escotilha superior, pois o bit correspondente nas informações do tipo de gráfico não está definido.
Aqui estão mais alguns sprites lindamente animados do jogo:
Interface do Usuário
Agora falta apenas a interface do usuário do jogo, que é feita em um estilo de metal escovado.
Mas também aqui é evidente que Dynamix não precisou reinventar a roda; aqui não são apenas utilizadas as APIs User32 e GDI32 fornecidas pelo Windows - em particular, também é gerenciado o uso de recursos do User32.
Esses recursos podem ser extraídos, por exemplo, por programas como o Resource Hacker, desenvolvido como freeware por Angus Johnson, ou - caso você evite usar Wine no Linux / Mac OS - com a ajuda do wrestool incluído no icoutils.
Nome do arquivo | Conteúdo |
---|---|
Outpost2.exe | Contém apenas o ícone do jogo, que mostra a estação espacial em New Terra |
op2shres.dll | Contém, além de gráficos para elementos de controle como bordas, botões, botões de rádio e caixas de seleção, também fundos de diálogo, imagens de apoio para os textos das missões da história e o gráfico de fundo do menu principal |
out2res.dll | Contém a decoração de janelas do jogo, ícones para metal comum e especial, a tela de carregamento, gráficos para diálogos, além de outros gráficos de cursor, além dos animados no diretório do jogo |