Plik pomocy do programu spr2bmp do gry Dark Colony (1997), twórca programu dreamerman.
Strona www: http://www.dreamerman.cba.pl/dctools.html
build z: 20 marca 2010, 19:40

Spis treści:

-do spisu-

Program

-do spisu-

O programie:

spr2bmp powstał aby pomóc, ułatwić pracę osobom, które chciałyby dokonać większych zmian w grze Dark Colony.
Do tej pory istniejące modyfikacje ograniczały się do nowych map, zmienionych statysty jednostek itd, teraz dzięki możlwiości edycji plików spr można także podmieniać grafikę, czcionki. Z tego co mi wiadomo spr2bmp jest jedynym programem, który potrafi dokonać konwersji spr>>png>>spr.
Dużą motywacją do napisania programu było aktywnie działające polskie forum DC Forum PL

Teraz sprawy techniczne:
język programowania: FreeBasic (FB)
edytor kodu: FB Edit
biblioteka do obsługi png: PNG library
biblioteka kompresji: zlib


-do spisu-

Katalogi w DC:

animate -> opisy animacji jednostek i efektów, menu
cursor -> grafika kursorow uzywanych w grze
gamtestat -> parametry jednostek, budynkow, broni
intrface -> grafika, palety i inne pliki używane do menu (np. czcionki)
scenario -> zawiera misje, mapy MP, jak również grafikę dla map (tile set's)
sound -> dzwięki
sprites -> grafika jednostek, efektów


-do spisu-

Co jest pomocne przy rozkodowywaniu?

Z samej gry:
2 wersje pliku z kursorami:
curs2.spr -> nie skompresowany
curs.spr -> skompresowany
dzięki porównywaniu ich można określić w jaki sposób działa tutaj kompresja, mimo różnej ilości obrazków w obu plikach.
palette.ppm - paleta dla większości plików, format .ppm - można zamienić na .bmp przez netpbm

Narzędzia własnego autorstwa:
'file reader' -> program pobierający dane z danego pliku, nie przejmując się nagłówkami itd, wyświetlający pobrane dane jako obrazek, którym można na bieżąco zmieniając wymiary i tryb wyświetlania
spr2bmp -> sam działający konwerter .spr na .bmp
dowolny sensowny program do porównywania binarnego 2 plików
(w pakiecie załączony mój program diff_my -> porównuje dwa pliki, w razie wystąpienie ponad 50 różnic kończy pracę)

Inne:
dowolny czytelny edytor heksadecymalny, najlepiej z wyszukiwaniem po tekście i wartościach hex/bin, ja używałem ICY Hexplorer.
HDSearchAndStats od Freebyte -> świetne do wyszukiwania plików


-do spisu-

Możliwości programu:

obsługiwane pliki - co zawiera - efekt działania programu:
spr -> obrazki-sprajty -> wyciąga grafikę z pliku i zapisuje w postaci bmp/png
bts -> obrazki (podłoże) dla map -> -||-
png -> obrazek / grupa obrazów -> tworzy kompatybilny z DC plik spr
fin -> opis animacji -> rozpisuje animację na postać tekstową (tylko to co jest w stanie rozpoznać, zazwyczaj trzeba ręcznie sprawdzać poprawność)
map -> plik mapy -> podgląd mapy podłoża mapy, bez jednostek itd
Uwaga! Aktualnie stworzenie pliku spr/bts jest możliwe tylko z plików png - kwestia napisania funkcji która ustali wielkość pliku bmp


-do spisu-

Konfiguracja programu:

Pewne funkcje wymagają określenia katalogu w którym znajduje się DC (aby nie trzeba było kopiować zbędnych plików), lokalizację gry należy podac w pliku 'setup.txt', przykładowa konfiguracja:
DCpath=D:\gry\Dark Colony
Należy zaznaczyć, że przy używaniu zewnętrznych palet (aktualnie jedynie przez linię poleceń) dana paleta musi się znajdować w tym samym katalogu co obrabiany plik.


Pliki gry

Poszczególne rodzaje plików, to co udało się z nich odczytać: Uwaga!! Często określając index (numer) danego elementu w tablicu czy też jego pozycję w programowaniu liczymy od 0 - jako pierwszy element. Jednak tutaj w wyjaśnieniach często używam numeracji liczonej od 1 - jako pierwszego elementu, jest to zazwyczaj napisane. W razie wątpliwości wystarczy włączyć hexeditor i poglądnąć jak to wygląda w pliku.


-do spisu-

--- Plik .spr ---

Oznaczenia aa, 00 itd oznaczają zapis heksadecymalny i oznaczają jeden bajt (256 bitów, 16x16) numer podanych bajtów podawany przyjmując, że pierwszy bajt ma index 1 - czsto w tablicach zaczyna się od 0, więc wtedy trzeba odjąc 1 od podanych wartości pozycji

nagłówek:
2 bajty - 01 00 -> zwykły plik - wersja 1
- 81 00 -> plik z kompresją - wersja 2
2 bajty - aa bb -> ilość obrazków = bb*256+aa

4 bajty: aa bb cc dd => długość zakodowanych danych, bez nagłówków itd.

dla skompresowanych to:
dd*256^3+cc*256^2+bb*256+aa + ilosc_obrazkow*4 = wielkosc_pliku_w_bajtach - poz_pierwszego_bajta_z_danymi

dla nie skompresowanych to:
dd*256^3+cc*256^2+bb*256+aa = wielkosc_pliku + 4* il_obrazkow - 776

768 bajtów z paletą RGB danego obrazka (3 * 256)
większość tych palet jest zbyt ciemna, aby zachować względną kompatybilność palety z plikiem palette.ppm należy każdy bajt (oprocz 0) pomnożyć razy 4 i dodać 3
np. pobieramy aa, if aa>0 then aa=aa*4+3

od bajta 777 rozpoczynają się wielkości poszczególnych obrazków:
4 bajty wymiarów + 4 bajty ustalające przesunięcie
aa bb cc dd + ee ff gg hh
szerokosc = bb * 256 + aa
wysokosc = dd * 256 + cc
przesuniecie_x = 144 - ee //przesuniecie w lewo od domyslnej pozycji, te wartości przesunięć są stosowane do jednostek
przesuniecie_y = 104 - gg //przesuniecie w górę -||-
możliwe, że 2 pozostałe bajty także mają znaczenie, jednak na razie daje się poprawnie odczytać animacje nie używając ich
przesuniecie_x należy liczyć inaczej gdy obrazek ma byc odwrócony:
wlasciwa_wartosc = -(szerokosc - 32 - przesuniecie_x)

Tutaj następuje podział ze względu na typ pliku - kompresja (2) lub czyste dane (1)

Wersja 1:
Dane o obrazkach następują zaraz po danych z wielkościami obrazków, a zatem ilość bajtów do pobrania = szerokosc * wysokosc
I tak obrazek za obrazkiem aż do końca.
To właściwie tyle z tym typem pliku .spr, w ten sposób są zapisane nieliczne pliki, głownie przyciski tekstowe, lub nieużywana grafika.

Wersja 2:
Dane każdego obrazka są poprzedzane 4 bajtami - ilość bajtów opisujących danych obrazek, po nich następuje skompresowany obrazek, korzystający z specyficznej wersji kodowania RLE.
ilość danych: aa bb cc dd - liczymy podobnie jak główną długość zakodowanych danych w pliku:
dd*256^3+cc*256^2+bb*256+aa = liczba_bajtow_opisujaca_dany_obrazek

sposób dekodowania:
pobieramy jeden bajt (a), jeżeli wartość ta jest mniejsza niż 128 to po tym bajcie następuje 1+a-tych czystych bajtów obrazka.
w przeciwnym wypadku (a >= 128) do obrazka należy wprowadzić 256-a pikseli koloru czarnego.
Tak to się kręci aż do dojścia do końca obrazka.

Przykład:
E2 02 42 41 41 -> dekodujemy tak:
E2(226) > 128, wprowadź 256-226=30 czarnych pikseli
02(2) < 128, 1+2=3 kolejne bajty to czyste dane, które wprowadzamy do obrazka
W ten sposób rozkodowujemy każdą partię bajtów.


Efektem działania spr2bmp są także następujące pliki:
palette.bmp -> 24bitowy (RGB) plik bmp o wielkości 256x1 zawierający wszystkie kolory z palety
pal_used.bmp -> parametry te same, jednak ten plik zawiera tylko te kolory z palety, które zostały użyte - pozostałe są zastąpione pierwszym kolorem (index 0)
build.txt -> informacje o sposobie rozkodowania pliku, plik konieczny do stworzenia pliku zgodnego z oryginalnym

opis build.txt:
pierwsza linia -> komentarz
druga linia -> czy to spr czy bts -> różnica w kodowaniu i zapisie
trzecia linia -> typ pliku prosty / skompresowany
czwarta linia -> czy zapisywać bufor po dojściu do krawędzi obrazka, wytłumaczenie poniżej

wśród skompresowany obrazków, jest jeszcze podział ze względu na sposób działania przy dojściu do krawędzi obrazka.
Załóżmy, że mamy obrazek o wymiarach 10x2,
zapisanie bufora następuje po dojściu do X, i oczywiście osiągnięciu maksymalnej długości bufora=128, oraz zmianie koloru czarny-reszta.
(z,n - normalne kolory, c - czarny)

zawijanie przy krańcu obrazka:
0123456789X
zzzzzccccc
ccccnnnnnn

opcja bez zawijania:
01234567890123456789X
zzzzzcccccccccnnnnnn

Jak widać, opcja bez zawijania jest oszczędniejsza, jednak w DC są używane obie formy, ze względów zgodności należy o tym pamiętać, bo gra nie toleruje obu sposobów przy poszczególnych grafikach.


-do spisu-

--- Plik .fin ---

Opis animacji poszczególnych jednostek i efektów.
Te pliki są duże, i zawierają sporo zbędnych danych, ciężko odkodować do czego są potrzebne niektóre bajty/dane.

kierunki obrotu jednostek

    8
  6 | 10
   \|/
 4--x--12
   /|\
  2 | 14
    0
1 i 2 bajt (0 i 1 od 0) nierozpoznane
3 i 4 bajt (2 i 3 od 0) ilość bloków środkowych - 3 blok, równe ilości klatek animacji
5 i 6 bajt (4 i 5 liczac od 0) ilośc blokow - 2 blok
7 bajt ilosc pierwszych blokow - 1 blok
nie jest wskazana długość bloku 4 - przynajmniej nie udało mi się tego odczytać


rodzaje blokow:
1: 4 bajty nazwa + 4 bajty odstep
-> nazwy używanych plików z grafiką, często są podawane nie używane pliki + odstęp
2: 16 bajtów + 4 bajty jakiegos znacznika
-> nazwa animacji + numery klatek animacji -> 2bajty początek, 2bajty koniec przedziału - potrzebne do identyfikacji przy odczytywaniu bloku 4
3: 4 bajty + 8x 20 bajtow
-> największe bloki, skupisko zbędnych i nierozpoznanych danych :>
4: 22 bajty
-> to co nas interesuje, opisany poniżej


Do odczytania animacji jednostek najważniejszy jest blok 4 dlatego go opiszę:
blok 4 - 22 bajty
               id obrazka-1 -> z pliku nazwa_grafiki.spr
                 |                       czy to glowna warstwa
                 |                       |    czy jest obrócone
  nazwa_grafiki  V                       V    V
6261727200000000 06 00 E0FF21 0000001000 0100 0100 - podstawa obrocona poziomo
6261727200000000 07 00 E4FF1F 0000001000 0100 0100 - podstawa obrocona poziomo
6261727200000000 13 00 61FF1E 0000001000 0100 0000 - podstawa normalna bez nakladki
6261727200000000 08 00 61FF1B 0000001000 0100 0000 - podstawa normalna
6261727200000000 18 00 61FF1E 0000001000 0100 0000 - podstawa normalna
6261727200000000 3B 00 61FF04 0000001000 0500 0000 - nakładka normalna
6261727200000000 3E 00 61FF02 0000001000 0500 0000 - nakładka normalna
6261727200000000 27 00 61FF1E 0000001000 0100 0000 - podkladka, na niej nakladka

nazwa_grafiki - z jakiego pliku .spr brac grafikę, najczęściej taka sama jak nazwa pliku .fin ale przy opisach efektów specjalnych np. lecące iskry z pojazu czy wybuchy podawane są inne pliki

Ogólnie odczytywanie wygląda tak: wczytujemy dane podstawowe animacji z bloku 2, pozniej przenosimy sie w pliku na początek 4 bloku i lecąc pętlą for zczytujemy opisy dla kazdej animacji do końca pliku.
Sporym problemem jest częsty brak opisów animacji, które zostały określone w bloku nr 2, dlatego dla ułatwienia wczytywania w nowych projektach powinno się przepisać potrzebne dane z pliku .fin do własnego ulepszonego formatu.


Efekt działania spr2bmp:
Ważne!! W plikach fin znajdują się zbędne animacje z bloku 2 - należy je pominąć, program pozwala pominąć jedną, przykładowo BLOOD w reap.spr, m.in. z tego powodu należy ręcznie przeglądnąć plik wynikowy w poszukiwaniu błędów odczytu.

Jak odczytać plik wynikowy?
przykład:

pozycja: 96
animacja nr: 0, nazwa: REAPSTAND0
klatki: 0-0

pozycja: 47400
pozycja w bloku 3: 1316
klatka nr: 0, źródło spr: reap.spr
nr obrazka: 1

pozycja oznacza index bajtu w pliku (podgląd przez hexeditor)
animacja - nr animacji, licząc od 0 jako pierwszy element,
klatki - nr klatki z bloku 4, licząc od 0 jako pierwszy element
nr obrazka -> dokładny nr obrazka z podanego pliku spr - taki sam jak nr obrazka po skonwertowaniu danego spr na bmp/png
pozostałe wartości sa chyba jasne

W razie otrzymania danych typu:
nakładka: .spr, nr obrazka: 113 itp. oznacza to, że animacja w tym momencie nie jest poprawna, trzeba przeglądnąć ręcznie w poszukiwaniu błędów, i tego co nalezy pominąć.


-do spisu-

--- Plik .bts ---

grafika dla map.

4 bajty nie rozpoznane
2 bajty (a może więcej) -> ilość obrazkow w pliku
od 9 bajta paleta - tak samo jak w plikach .spr

od 777 bajta następują dane obrazków
4 bajty -> id obrazka - wykorzystywane są 2 bajty
1024 bajty -> dane obrazka

każdy obrazek 32x32 = 1024 bajty

Efekt działania spr2bmp:
wynik działania podobny jak w przypadku plików .spr
Dodatkowo tworzony jest plik nazwa_terenu.txt, zawiera on informacje o id poszczególnych bloków z oryginalnego pliku bts (konieczne m.in. do ponownego utworzenia bts).
przykład:
302 ; 1
305 ; 2

pierwsza liczba to id, druga to numer danego bloku - aby użytkownikowi łatwiej było przeglądać te dane.


-do spisu-

--- Plik .map ---

Mapy z DC.

4 bajty szerokosc
4 bajty wysokosc

blok danych o poszczególnych kwadracikach mapy
2 bajty -> tylnia grafika
2 bajty -> wierzchnia grafika
powyższe dane zwierają id bloczów, które należy wstawić w dane miejsce na mapie, to id jest zapisane przy każdym bloczku w pliku .bts

po wczytaniu całej mapy następuje następny pakiet danych dla każdego pola mapy
2 bajty -> opisują dodatkowe parametry bloczka
pierwszy bajt opisuje obrót bloczka (jest lub nie ma), informację o 'wysokości' oraz czy blokowane jest pole widzenia
drugi bajt zawiera informację, czy należy blokować poruszanie się, oraz czy pole ma właściwości kamuflażu
Trzeba to jeszcze przeglądnąć i w razie czego poprawić.

1 bajt
zakresy dla obrotu (zakresy ponieważ w tym bajcie także jest opisana 'wysokość)
- obrót obu warstw: (96, 100) v (223, 228) v (63, 68) v [193]
- obrót spodniej warstwy: [161] v (159, 163) v (223, 228) v (95, 100) v [32] v [193]
blokowanie pola widzenia: jeżeli wartość bajta < 128 to należy zablokować

2 bajt
blokowanie poruszania się - bajty: [2, 14, 18, 30, 6, 54, 42, 50, 90, 58, 78, 82, 46, 66, 62, 70]
kamuflaż - bajty: [49, 77, 89]


Efekt działania spr2bmp:
wskazujemy dowolną mapę, wybieramy jednostkę która ma być wyświetlana (w miarę poprawnie są obsługiwane TRSC, REAP, BARR) i typ podkładu dla mapy -> desert, jungle, special. Podkład musi być pod dany typ mapy, inaczej program się wysypie.
sterowanie w trybie podglądu mapy:
strzałki -> przesuwanie mapy
q -> wyświetla pomocnicze linie, przydatne do określenia granicy danego pola
w -> zmienia tryb wyświetlania -> normalny / podgląd specjalny / atrybuty pól - zgodne z tym co wyświetla edytro map DC
d/f/m -> przełącza na inną animacje jednostki śmierć/strzał/ruch
cyfry 1-9 -> okresla kierunek animacji jednostki - zgodne z kierunkami na klawiaturze alfa-numerycznej
Esc -> wyłączenie podglądu


-do spisu-

--- Plik .scn ---

tekstowo zapisane dane o poszczegolnych drużynach nastepnie:

poz_x
wys - poz_y
unit_type -> id z gamestat.txt
team -> 0 czerw, 1 nieb
? -1
? 0


-do spisu-

--- Inne ---

Palety.
Pierwszy kolor palety (licząc od 0 ma index 0) oznacza przeźroczystość.

Animacja wody.
Podmianie ulegają kolory od 201 do 207 (wlącznie).
Mamy tablicę 7 oryginalnych kolorów i wklejamy je do aktualnej palety w miejsce 201+i, przy czym i przy każdej 'klatce' animacji zwiększa się o 1, jeżeli przekoczy 201+i>207 to należy zmniejsych i o 6.
Należy pamiętać o tym, że każdy z podmienianych kolorów musi zastąpić inny z podanej granicy, dlatego każda podmiana musi być sprawdzana czy index wyszedł ponad 207.
Przykładowy kod animacji wody w źródle spr2bmp.

To chyba tyle. ;]

Inne

-do spisu-

--- Tworzenie/edytowanie pliku spr ---

Wybieramy dowolny plik spr, korzystamy z opcji 'centruj grafikę', i wybieramy format png (aktualnie z bmp nie można utworzyć spr).
Dokonujemy zmian/edycji wynikowych plikach png/bmp.
Uruchamiamy ponownie spr2bmp, wskazujemy jeden z plików png/bmp przygotowanych wcześniej, w katalogu musi być plik build.txt, oraz plik z paletą, która ma zostać użyta -> palette.bmp
Mogą pojawić się niezgodności z oryginalnym plikiem, spowodowane jest to powtarzaniem się kolorów w wbudowanej w plik palecie, niezgodności w paletach.


-do spisu-

--- Linia poleceń ---

Inaczej mówiąc parametry z jakimi można odpalić program:
pierwszy parametr musi być nazwą pliku wejściowego
-p plik.typ -> używaj palety zawartej w podanym pliku, tylko 24bitowe bmp wielkości 256x1, działa tylko przy spr>>png/bmp
-r -> traktuj plik wejściowy jako czyste dane
np.
spr2bmp reap.spr -p paleta2.bmp
takie wywołanie skonwertuje reap.spr na png/bmp używając palety z pliku paleta2.bmp


-do spisu-

--- Działanie pod Linuxem ---

spr2bmp jest napisany w języku FreeBasic, jest to nowoczesny darmowy multi-platformowy kompilator basic.
W samym kodzie jedyną funkcją używającą czysto Win Api jest wywołanie okna do wybrania katalogu (jest także alternatywna funkcja pobrania nazwy pliku poprzez konsole), reszta kodu powinna działać także pod Linuxem.
Należy nadmienić, że w kodzie używam slashy z Windowsa także możliwe, że trzeba je będzie zamienić na odwrotne.
Uruchamiając kod pod lin trzeba zmienić poniższą definicję:
#Define sys_op "win"
'win' -> na dowolne inne określenie, najlepiej 'lin', wtedy użyty zostanie kod multiplatformowy
Ze względów technicznych nie mogłem przygotować sprawdzonej wersji dla Linuxa.



by dreamerman :-)