-
Notifications
You must be signed in to change notification settings - Fork 0
stationsTut
EN PL |
Pokaż pełny zestaw ramek, aby ułatwić nawigację (en.)
- Introduction
- Przykłady
- Przykład 1: Prosta stacja
- Przykład 2: Współdzielone układy i struktury układów
- Przykład 3: Animacja
Introduction |
Stacje są istotną funkcją TTD, a od TTDPatch 2.0.1 a6 (10 listopada 2003) możliwe jest kodowanie stacji niestandardowych. Chociaż kodowanie stacji jest nieco trudniejsze niż kodowanie pojazdów, w m4nfo jest o wiele prostsze niż robienie tego w zwykłym nfo.
Najważniejszą różnicą w porównaniu z kodowaniem pojazdów jest to, że stacje mają nie tylko grafikę i dostęp do szeregu zmiennych gry TTD w taki sam sposób, jak pojazdy, ale także wykorzystują sprite i układ kafli, wprowadzając w ten sposób informacje 3D. Daje to szereg możliwości 'recyklingu' układów sprite'ów lub kafli w kodzie, co może sprawić, że stacje kodujące będą całkiem wydajne.
Przykłady |
Przykład 1: Prosta stacja |
Pierwszą rzeczą do zrobienia byłoby w ogóle zdefiniowanie stacji. W m4nfo odbywa się to za pomocą funkcji definestation() i oto ona:
definestation(ENGINESHED,"Engine shed", class(DEPOT) callbacks(CB_LAYOUT) exclude_widths(8) exclude_lengths(8) pylons(TTD_ALLTILES) flags(FOUNDATIONS) ) |
Jak widać na liście parametrów funkcji, ID tej stacji to "ENGINESHED" (pewna liczba zdefiniowana w innym miejscu), a jej (domyślna) nazwa to "Engine sheds".
Teraz w treści funkcji można znaleźć więcej funkcji właściwości, definiujących jeszcze więcej atrybutów tej stacji:
- class(DEPOT) ustawia ID-klasy stacji na "DEPOT" , aby poprawnie umieścić go w odpowiedniej klasie wewnątrz menu budowania stacji,
- callbacks (CB_LAYOUT) aktywuje callback CB_LAYOUT dla tej stacji, aby obsłużyć jej układ kafli,
- exclude_widths(8) i exclude_lengths(8) określają liczbę i długość możliwych platform stacji do zbudowania za jednym zamachem, tj. pozwala na liczbę platform od 1 do 7, a długość tych platform również od 1 do 7
- pylony (TTD_ALLTILES) pozwalają na rysowanie pylonów trakcyjnych na wszystkich 'typach kafli' TTD ,
- flagi ('FUNDAMENTY') nakazują grze, aby automatycznie dodawała niestandardowe (gotowe) fundamenty zamiast standardowych fundamentów gry dla tej stacji, gdy jest budowana na zboczach
classnames(DEPOT,{US, "Locomotive depot"}, {D, "Bahnbetriebswerk"}, {F, UTF8 "Dépôt de locomotives"}, {E, UTF8 "Depósitos de locomotoras"}, {NL, "Locomotief depot"}, {I, "Rimesse locomotive"}, {PL, "Parowozownia"}, {HR, "Depo za lokomotive"}, {S, "Lokverkstad"}, {H, UTF8 "Mozdonyszín"}, {RUS, UTF8 "Локомотивное депо"} stationnames(ENGINESHED,{US, "Engine sheds"}, {D, "Lokschuppen"}, {F, UTF8 "Remises à locomotives"}, {E, "Naves de locomotoras"}, {NL, "Locomotiefloods"}, {I, "Rimesse per locomotive"} {PL, "Lokomotywownie"}, {HR, "Remiza za lokomotive"}, {S, "Lokstaller"}, {H, UTF8 "Mozdonyszín"}, {RUS, UTF8 "Локомотивное депо"} ) |
Teraz trzeba zdefiniować niektóre prawdziwe (graficzne) 'sprites', robi się to w m4nfo w następujący sposób:
spriteblock( set(// [0 .. 5] locomotive shed sprite(shed5.pcx 10 10 09 16 21 -31 4) sprite(shed5.pcx 35 10 09 27 43 -32 -7) sprite(shed5.pcx 80 10 09 41 66 -31 1) sprite(shed5.pcx 150 10 09 41 66 -33 1) sprite(shed5.pcx 220 10 09 27 43 -9 -7) sprite(shed5.pcx 270 10 09 16 21 12 4) ...// [10 .. 13] walls & doors sprite(shed5.pcx 10 110 09 18 15 0 0) sprite(shed5.pcx 28 110 09 18 15 0 0) sprite(shed5.pcx 46 110 09 18 15 0 0) sprite(shed5.pcx 64 110 09 18 15 0 0)// [14 .. 15] locomotive shed (snowy roof) sprite(shed5.pcx 10 130 09 41 66 -31 1) sprite(shed5.pcx 80 130 09 41 66 -33 1) ...// [18 .. 19] icon locomotive shed sprite(shed5.pcx 10 223 09 46 66 -31 -15) sprite(shed5.pcx 80 223 09 46 66 -31 -15) ... ) ) def(1) spriteset(little(0),lots(0)) |
Sprite'y #0 i #1 to grafika platformy, #0 to tylna platforma, a #1 to przednia platforma. Sprite #2 to dach szopy. Teraz TTD narysuje te sprite'y we właściwej kolejności, aby uniknąć błędów graficznych w grze. Osiąga się to poprzez uwzględnienie informacji 3D, które zostaną podane później w funkcji layout(). W każdym razie sprite #0 zostanie narysowany jako pierwszy, następnie zostaną narysowane pojazdy pociągów, potem sprite #1, z 'dachem' (#2) na końcu.
Zwróć uwagę, że "nadmiernie niebieski" dla 'dachowych' 'sprites' #2 i #3. Jest to potrzebne, aby móc ustawić drzwiczki podrzędne drzwi i ściany w taki sposób, aby całkowicie pasowały do granic ich 'nadrzędnego sprite' (tego 'sprite' 'dachowego').
Funkcja spriteset() w def(1) zbiera wszystkie podane 'sprites' i udostępnia je w łańcuchu kontroli, który ma zostać ustawiony. Ponieważ nie ma stanów ładowania ładunku dla tego typu stacji, oba jej parametry są zerowane przez funkcje pomocnicze little() i lots().
Teraz, gdy potrzebne sprite'y zostały zdefiniowane w funkcji "spriteblock", potrzebujemy środków, aby [stationFunctions#examples]] z ich poszczególnych 'sprites'. Odbywa się to za pomocą funkcji layout(). Jego pierwszym parametrem jest ID-stacji powiązany z tym konkretnym układem, po którym następuje blok definicji kafli:
layout(ENGINESHED,
// [0 .. 1] open tile(_open,ground(1012) regular(0, xyz(0,0,0),dxdydz(16,5,7)) regular(1, xyz(0,11,0),dxdydz(16,5,7)) regular(2, xyz(0,0,16),dxdydz(16,16,26)) // roof ) tile(ground(1011) regular(5, xyz(0,0,0),dxdydz(5,16,7)) regular(4, xyz(11,0,0),dxdydz(5,16,7)) regular(3, xyz(0,0,16),dxdydz(16,16,26)) // roof // [2 .. 3] closed tile(_closed,ground(1012) regular(0, xyz(0,0,0),dxdydz(16,5,7)) regular(1, xyz(0,11,0),dxdydz(16,5,7)) regular(2, xyz(0,0,16),dxdydz(16,16,26)) // roof regular(10, xyoff(8,23)) // wall ) tile(ground(1011) regular(5, xyz(0,0,0),dxdydz(5,16,7)) regular(4, xyz(11,0,0),dxdydz(5,16,7)) regular(3, xyz(0,0,16),dxdydz(16,16,26)) // roof regular(11, xyoff(43,23)) // wall // [4 .. 5] door closed tile(_door_closed,ground(1012) regular(0, xyz(0,0,0),dxdydz(16,5,7)) regular(1, xyz(0,11,0),dxdydz(16,5,7)) regular(2, xyz(0,0,16),dxdydz(16,16,26)) // roof regular(12, xyoff(8,23)) // door ) tile(ground(1011) regular(5, xyz(0,0,0),dxdydz(5,16,7)) regular(4, xyz(11,0,0),dxdydz(5,16,7)) regular(3, xyz(0,0,16),dxdydz(16,16,26)) // roof regular(13, xyoff(43,23)) // door // snow // [6 .. 7] open tile(_open_snow,ground(1012) regular(0, xyz(0,0,0),dxdydz(16,5,7)) regular(1, xyz(0,11,0),dxdydz(16,5,7)) regular(14, xyz(0,0,16),dxdydz(16,16,26)) // roof ) tile(ground(1011) regular(5, xyz(0,0,0),dxdydz(5,16,7)) regular(4, xyz(11,0,0),dxdydz(5,16,7)) regular(15, xyz(0,0,16),dxdydz(16,16,26)) // roof // [8 .. 9] closed tile(_closed_snow,ground(1012) regular(0, xyz(0,0,0),dxdydz(16,5,7)) regular(1, xyz(0,11,0),dxdydz(16,5,7)) regular(14, xyz(0,0,16),dxdydz(16,16,26)) // roof regular(10, xyoff(8,23)) // wall ) tile(ground(1011) regular(5, xyz(0,0,0),dxdydz(5,16,7)) regular(4, xyz(11,0,0),dxdydz(5,16,7)) regular(15, xyz(0,0,16),dxdydz(16,16,26)) // roof regular(11, xyoff(43,23)) // wall // [10 .. 11] door closed tile(_door_closed_snow,ground(1012) regular(0, xyz(0,0,0),dxdydz(16,5,7)) regular(1, xyz(0,11,0),dxdydz(16,5,7)) regular(14, xyz(0,0,16),dxdydz(16,16,26)) // roof regular(12, xyoff(8,23)) // door ) tile(ground(1011) regular(5, xyz(0,0,0),dxdydz(5,16,7)) regular(4, xyz(11,0,0),dxdydz(5,16,7)) regular(15, xyz(0,0,16),dxdydz(16,16,26)) // roof regular(13, xyoff(43,23)) // door // [12 .. 13] icons tile(_icon,ground(1012) regular(18, xyz(0,0,0),dxdydz(16,16,1)) ) tile(ground(1011) regular(19, xyz(0,0,0),dxdydz(16,16,1)) ) ) |
Jak widać, są powiązane pary kafli, jedna w kierunku x, a druga w kierunku y. Każdy kafel składający się z 'sprite gruntu', reprezentującego ścieżkę (sprite'y TTD 1011 i 1012) oraz jednego lub więcej 'sprites budowlanych', reprezentujących tylną lub przednią ścianę oraz dach. Należy również pamiętać, że funkcja kafla może otrzymać opcjonalną etykietę ułatwiającą odniesienie do tego konkretnego kafla.
Każdy z tych 'sprites' jest opisany przez kolejny numer, powiązany z jego rangą w graficznym bloku sprite'ów, trójwymiarową współrzędną, wskazującą jego położenie w przestrzeni 3D oraz jego rozmiar w x, y i wysokość. Niektóre z tych 'sprites' to tak zwane 'sprites' 'potomne', które nie mają ani współrzędnych, ani rozmiarów, ale zamiast tego definiują dwuwymiarowe 'przesunięcie' względem lewego górnego rogu ich nadrzędnych 'sprites', dzieląc trójwymiarową ramkę 'nadrzędną'. Oceniając te liczby, sortownik sprite'ów TTD narysuje sprite'y we właściwej kolejności, odcinając (które mają być) ukryte części
Teraz kafle #0 i #1 (etykieta "_open") reprezentują otwartą szopę (zarówno w kierunku x, jak i y), kafle #2 i #3 ("_closed") wyświetlają szopę bez wpisu, stosując tzw. nazywane 'podrzędnym sprite' dla 'dachowego' 'sprite', kafla #4 i #5 ("_door_closed") robią to samo, ale z grafiką zamkniętych drzwi zamiast ściany, kaflami #6/#7, #8/#9 i #10/#11 są takie same tylko ze śnieżnym 'dachem', a kafle #12/#13 ("_icon") stanowią ikony potrzebne w menu budynku.
Po przygotowaniu potrzebnych grafik i ich układu będziemy musieli zbudować 'łańcuch kontroli' , łącząc grafikę i układ z ID-stacji, a także zająć się funkcjonalnością szopy.
Pierwszą rzeczą, którą chcemy osiągnąć, jest dostosowanie wyglądu szopy w przypadku podłączenia do niej toru. Jeśli przed szopą nie ma toru, powinien przedstawiać prostą ścianę bez drzwi. Drugą cechą, którą chcemy zakodować, jest to, że w przypadku, gdy do szopy prowadzi tor, drzwi szopy powinny otwierać się tylko wtedy, gdy pociąg wjeżdża do lub z szopy.
Pierwsza funkcja będzie obsługiwana przez funkcję m4nfo tinfo_trackconnect(), a druga jest obsługiwana przez funkcję pbsinfo() .
Ostatnią rzeczą, którą należy zrobić, jest narysowanie niestandardowych fundamentów podczas budowy na zboczu i pokazanie śnieżnej grafiki podczas budowania na zaśnieżonym terenie. Pierwsza jest obsługiwana przez funkcję spritetype(), druga za pomocą funkcji tinfo_terrain() .
Oto kod:
def(0) spritetype( ref(CF_NORMAL) if(2) // custom foundation ref(1) else // normal ground or building sprite ) def(6) pbsinfo( reftile(_open) if(PBSRESERVED) // open reftile(_door_closed) else // closed ) def(7) tinfo_trackconnect(shiftmask(0,1), ref(6) if(1) // track from below reftile(_closed) else // no track, show wall ) // snow def(6) pbsinfo( reftile(_open_snow) if(PBSRESERVED) // open reftile(_door_closed_snow) else // closed ) def(8) tinfo_trackconnect(shiftmask(0,1), ref(6) if(1) // track from below reftile(_closed_snow) else // no track, show wall ) // check for snow def(9) tinfo_terrain( ref(8) if(SNOW) // snow ref(7) else // no snow ) def(10) callback( ref(9) if(CB_LAYOUT) // tile layout ref(0) else // graphics chain ) // menu def(11) callback( reftile(_icon) if(CB_LAYOUT) // tile layout ref(0) else // graphics chain ) makestation(ENGINESHED, link(ref(11), MENU) default(ref(10)) ) |
A teraz podsumujmy, co zrobiliśmy. Jak zwykle zacznijmy od końca, od funkcji makestation().
Ta funkcja łączy się z dwoma łańcuchami, jednym łańcuchem do wpisu w menu budynku, a łańcuch główny stanowi opis stacji w grze. Teraz łańcuch dla pozycji menu jest prosty: w przypadku CB_LAYOUT, pokaże kafel (y) #12/#13 z układu (tj. Ikona), a w przeciwnym razie będzie odnosił się do def(0), który reprezentuje zarówno główny zestaw grafik, jak i niestandardowy podstawowy zestaw grafik. Ponieważ w menu nie ma potrzeby stosowania fundamentu, w menu zostaną wyświetlone grafiki kafli #12/13.
Teraz spójrzmy teraz na główny ('domyślny') łańcuch. Najpierw (w def(10)) sprawdzamy również callback CB_LAYOUT. W przypadku braku wywołania zwrotnego, ponownie łączymy się z def(0) i pokazujemy odpowiednią grafikę, albo niestandardowe sprite'y fundacji (w przypadku, gdy spritetype() zwraca "2") lub po prostu budujemy sprite'y.
W przypadku CB_LAYOUT sprawdzamy śnieżny teren (w def(9) ). W przypadku śniegu, przykuwamy do def(8), a jeśli nie ma śniegu, łańcuch przechodzi z def(7). Ponieważ oba łańcuchy zasadniczo robią to samo, dokładniej opisano tylko łańcuch bez śniegu.
Po pierwsze, w def(7) sprawdzamy połączenie torów z drzwiami wejściowymi szopy. Odbywa się to poprzez wywołanie funkcji tinfo_trackconnect(). Aby sprawdzić tylko ścieżkę prowadzącą do (widocznych) drzwi wejściowych, będziemy musieli sprawdzić bit0 zwracany przez tę funkcję. Odbywa się to poprzez sprawdzenie wyniku funkcji tylko dla tego bitu, co można zrobić za pomocą funkcji pomocniczej shiftmask() . W przypadku, gdy ścieżka istnieje, przechodzimy do def(6) sprawdzania stanu PBS, a w przypadku braku ścieżki, po prostu pokazujemy zwykłą ścianę, zwracając kafel #2 do wywołania zwrotnego.
Funkcja pbsinfo() w def(6) kwestionuje stan PBS, a w przypadku PBSRESERVED (tj. Ścieżka została zarezerwowana przez pathfinder), lubimy wyświetlać kafel #0 (drzwi otwarte), w przeciwnym razie kafel #4 (drzwi zamknięte) jest pokazane.
I to wszystko w tym przykładzie. W następnym rozwiniemy ten, aby pokazać, jak wiele podobnych typów stacji może być obsługiwanych przy użyciu tej samej struktury, tylko przez wprowadzenie pewnych rozszerzeń w układzie kafli stacji.
W przypadku stacji układ v jest oddzielony od prawdziwych sprite'ów zdefiniowanych w spriteblock() i dostępny za pomocą funkcji spriteset(). Otwiera to interesujące możliwości udostępniania układów v lub spriteów między stacjami. W tym drugim przykładzie chcemy rozszerzyć stację z przykładu 1 o inną podobną stację ("stary magazyn", patrz zdjęcie po lewej), w taki sposób, aby układy kafli dla obu różniły się tylko adresami sprite'ów. W ten sposób druga stacja nie potrzebuje własnego łańcucha sterowania, ale może używać tego z pierwszej stacji.
Pierwszą rzeczą do dodania byłaby definicja drugiej stacji, jak powyżej.
definestation(ENGINESHED,{"Engine sheds", "Old warehouses"}, class(DEPOT, PIECEGOODS) callbacks(CB_LAYOUT, CB_LAYOUT) exclude_widths(8, 8) exclude_lengths(8, 8) pylons(TTD_ALLTILES, TTD_ALLTILES) flags(FOUNDATIONS, FOUNDATIONS) ) |
Jak widać, funkcja definestation() może obsługiwać więcej niż jedną definicję stacji. W tym przypadku ID drugiej stacji zostałby przydzielony automatycznie, tzn. Będzie to ENGINESHED + 1. Ponieważ druga stacja powinna mieć inną klasę, musimy dodać nową klasę i nazwy stacji dla tej stacji.
classnames(PIECEGOODS,{US, "Freight stations (piece goods)"}, {D, UTF8 "Güterbahnhöfe (Stückgut)"}, {F, "Gares de marchandises (r.o.)"}, {E, UTF8 "Estaciónes de mercancías (bulto)"}, {NL, "Goederenloodsen (stukgoederen)"}, {I, "Scali merci (collettame)"}, {PL, "Stacje towarowe (drobnica)"}, {HR, "Teretne stanice (komadni teret)"}, {S, "Godsstationer (styckegods)"}, {H, UTF8 "Teherpályaudvar (darabáru)"}, {RUS, UTF8 "Грузовые станции (товары)"} ) stationnames(ENGINESHED+1,{US, "Old warehouses"}, {D, UTF8 "alte Lagerhäuser"}, {F, UTF8 "Vieux entrepôts"}, {E, "Almacenes viejos"}, {NL, "Oude magazijnen"}, {I, "Vecchi magazzini"} {PL, "Stare magazyny"}, {HR, UTF8 "Stara skladišta"}, {S, "Packhus"}, {H, UTF8 "Régi raktár"}, {RUS, UTF8 "Старые склады"} ) |
Ponownie, sprite'y graficzne muszą zostać zdefiniowane, tym razem dla obu stacji:
spriteblock( set(// [0 .. 5] locomotive shed sprite(shed5.pcx 10 10 09 16 21 -31 4) sprite(shed5.pcx 35 10 09 27 43 -32 -7) sprite(shed5.pcx 80 10 09 41 66 -31 1) sprite(shed5.pcx 150 10 09 41 66 -33 1) sprite(shed5.pcx 220 10 09 27 43 -9 -7) sprite(shed5.pcx 270 10 09 16 21 12 4) // [6 .. 9] old warehouse sprite(shed5.pcx 35 60 09 27 43 -32 -7) sprite(shed5.pcx 80 60 09 44 64 -31 -2) sprite(shed5.pcx 150 60 09 44 64 -31 -2) sprite(shed5.pcx 220 60 09 27 43 -9 -7) // [10 .. 13] walls & doors sprite(shed5.pcx 10 110 09 18 15 0 0) sprite(shed5.pcx 28 110 09 18 15 0 0) sprite(shed5.pcx 46 110 09 18 15 0 0) sprite(shed5.pcx 64 110 09 18 15 0 0)// [14 .. 15] snowy roof locomotive shed sprite(shed5.pcx 10 130 09 41 66 -31 1) sprite(shed5.pcx 80 130 09 41 66 -33 1) // [16 .. 17] snowy roof warehouse sprite(shed5.pcx 10 175 09 44 64 -31 -2) sprite(shed5.pcx 80 175 09 44 64 -31 -2) // [18 .. 19] icon locomotive shed sprite(shed5.pcx 10 223 09 46 66 -31 -15) sprite(shed5.pcx 80 223 09 46 66 -31 -15) // [20 .. 21] icon warehouse sprite(shed5.pcx 10 273 09 49 64 -31 -18) sprite(shed5.pcx 80 273 09 49 64 -31 -18) ) ) def(1) spriteset(little(0),lots(0)) |
Zestaw 'sprites' jest taki sam, jak w przykładzie 1, z dodawaniem tylko starych 'sprites' magazynu.
Ponownie, potrzebne sprite'y dla drugiej stacji zostały zdefiniowane w funkcji "spriteblock", należy zdefiniować nowy układ dla drugiej stacji:
layout(ENGINESHED +1,// [0 .. 1] open tile(_open, ground(1012) regular(0, xyz(0,0,0),dxdydz(16,5,7)) regular(6, xyz(0,11,0),dxdydz(16,5,7)) regular(7, xyz(0,0,16),dxdydz(16,16,26)) // roof ) tile( ground(1011) regular(5, xyz(0,0,0),dxdydz(5,16,7)) regular(9, xyz(11,0,0),dxdydz(5,16,7)) regular(8, xyz(0,0,16),dxdydz(16,16,26)) // roof )// [2 .. 3] closed tile(_closed, ground(1012) regular(0, xyz(0,0,0),dxdydz(16,5,7)) regular(6, xyz(0,11,0),dxdydz(16,5,7)) regular(7, xyz(0,0,16),dxdydz(16,16,26)) // roof regular(10, xyoff(8,26)) // wall ) tile( ground(1011) regular(5, xyz(0,0,0),dxdydz(5,16,7)) regular(9, xyz(11,0,0),dxdydz(5,16,7)) regular(8, xyz(0,0,16),dxdydz(16,16,26)) // roof regular(11, xyoff(43,26)) // wall )// [4 .. 5] door closed tile(_door_closed, ground(1012) regular(0, xyz(0,0,0),dxdydz(16,5,7)) regular(6, xyz(0,11,0),dxdydz(16,5,7)) regular(7, xyz(0,0,16),dxdydz(16,16,26)) // roof regular(12, xyoff(8,26)) // door ) tile( ground(1011) regular(5, xyz(0,0,0),dxdydz(5,16,7)) regular(9, xyz(11,0,0),dxdydz(5,16,7)) regular(8, xyz(0,0,16),dxdydz(16,16,26)) // roof regular(13, xyoff(43,26)) // door ) // snow// [6 .. 7] open tile(_open_snow, ground(1012) regular(0, xyz(0,0,0),dxdydz(16,5,7)) regular(6, xyz(0,11,0),dxdydz(16,5,7)) regular(16, xyz(0,0,16),dxdydz(16,16,26)) // roof ) tile( ground(1011) regular(5, xyz(0,0,0),dxdydz(5,16,7)) regular(9, xyz(11,0,0),dxdydz(5,16,7)) regular(17, xyz(0,0,16),dxdydz(16,16,26)) // roof )// [8 .. 9] closed tile(_closed_snow, ground(1012) regular(0, xyz(0,0,0),dxdydz(16,5,7)) regular(6, xyz(0,11,0),dxdydz(16,5,7)) regular(16, xyz(0,0,16),dxdydz(16,16,26)) // roof regular(10, xyoff(8,26)) // wall ) tile( ground(1011) regular(5, xyz(0,0,0),dxdydz(5,16,7)) regular(9, xyz(11,0,0),dxdydz(5,16,7)) regular(17, xyz(0,0,16),dxdydz(16,16,26)) // roof regular(11, xyoff(43,26)) // wall )// [10 .. 11] door closed tile(_door_closed_snow, ground(1012) regular(0, xyz(0,0,0),dxdydz(16,5,7)) regular(6, xyz(0,11,0),dxdydz(16,5,7)) regular(16, xyz(0,0,16),dxdydz(16,16,26)) // roof regular(12, xyoff(8,26)) // door ) tile( ground(1011) regular(5, xyz(0,0,0),dxdydz(5,16,7)) regular(9, xyz(11,0,0),dxdydz(5,16,7)) regular(17, xyz(0,0,16),dxdydz(16,16,26)) // roof regular(13, xyoff(43,26)) // door )// [12 .. 13] icons tile(_icon, ground(1012) regular(20, xyz(0,0,0),dxdydz(16,16,1)) ) tile( ground(1011) regular(21, xyz(0,0,0),dxdydz(16,16,1)) ) ) |
Jak widać, struktura układu jest identyczna jak w ENGINESHED, tylko numery 'sprites' są różne.
Teraz, gdy druga stacja używa tego samego układu kafli, co pierwsza stacja i oczywiście wymaga tego samego zachowania, co pierwsza, jeśli chodzi o połączenie torów, otwieranie drzwi i rozpoznawanie terenu, dodatkowy kod staje się dość mały:
def(0) spritetype( ref(CF_NORMAL) if(2) // niestandardowy fundament ref(1) else // normalny grunt lub sprite budynku ) def(6) pbsinfo( reftile(_open) if(PBSRESERVED) // open reftile(_door_closed) else // closed ) def(7) tinfo_trackconnect(shiftmask(0,1), ref(6) if(1) // track od dołu reftile(_closed) else // bez toru, pokaż ścianę ) // snow def(6) pbsinfo( reftile(_open_snow) if(PBSRESERVED) // open reftile(_door_closed_snow) else // closed ) def(8) tinfo_trackconnect(shiftmask(0,1), ref(6) if(1) // track od dołu reftile(_closed_snow) else // bez toru, pokaż ścianę ) // check for snow def(9) tinfo_terrain( ref(8) if(SNOW) // snow ref(7) else // no snow ) def(10) callback( ref(9) if(CB_LAYOUT) // tile layout ref(0) else // łańcuch graficzny ) // menu def(11) callback( reftile(_icon) if(CB_LAYOUT) // tile layout ref(0) else // graphics chain ) makestation(ENGINESHED, link(ref(11), MENU) default(ref(10)) )// dodatkowy kod dla stacji "stary magazyn" makestation(ENGINESHED+1, link(ref(11), MENU) default(ref(10)) ) |
To wszystko! Ponieważ nowa stacja używa dokładnie tego samego kodu i tych samych wskaźników do struktury sprite i layoutu. Jedyną różnicą są rzeczywiste liczby 'sprites'v w układzie kafli.
Jest więcej możliwości. Jednym z nich jest użycie tych samych układów zawierających nawet te same rzeczywiste liczby 'sprites', używając dwóch różnych bloków sprite'ów z prawdziwymi 'sprites'. W tym przypadku potrzebny jest tylko jeden układ kafli, który zostanie skopiowany przez funkcję copylayout() dla innych ID-stacji. Zostanie to pokazane w następnym przykładzie.
Przykład 3: Animacja |
Po raz kolejny pierwszą rzeczą do zrobienia byłoby zdefiniowanie stacji, tym razem zawierającej specjalne definicje animacji:
definestation(ANIMTEST,{"animation test"}, class(DEPOT) callbacks(CB_LAYOUT) include_widths(1) include_lengths(1) setcargotriggers({PASS, MAIL}) anim_info({8,LOOP}) anim_triggers({ARRIVE, LEAVE}) anim_speed(2) )
Większość definicji powinna być już znana, z wyjątkiem tych specyficznych dla animacji.
- anim_info({8,LOOP}) określa liczbę klatek animacji do wykorzystania, a także charakter animacji: zapętlony lub niepętlowy,
- anim_triggers({ARRIVE, LEAVE}) definiuje wyzwalacze do użycia w tej animacji. Tutaj definiujemy dwa wyzwalacze: jeden dla przyjeżdżających pociągów, a drugi dla wyjeżdżających pociągów,
- anim_speed(2) ustawia prędkość animacji, tj. umiarkowanie dużą.
Graficzne 'sprites' są definiowane w zwykły sposób:
spriteblock(
set(sprite(animtest.pcx 10 10 09 31 64 -31 0) // 0 sprite(animtest.pcx 78 10 09 31 64 -31 0) // 1 sprite(animtest.pcx 146 10 09 31 64 -31 0) // 2 sprite(animtest.pcx 214 10 09 31 64 -31 0) // 3 sprite(animtest.pcx 10 48 09 31 64 -31 0) // 4 sprite(animtest.pcx 78 48 09 31 64 -31 0) // 5 sprite(animtest.pcx 146 48 09 31 64 -31 0) // 6 sprite(animtest.pcx 214 48 09 31 64 -31 0) // 7 ) ) def(1) spriteset(little(0),lots(0)) |
W następnym kroku należy ustawić układ kafli przy użyciu 'sprites' zdefiniowanych powyżej:
layout(ANIMTEST, // [0/1] tile( ground(1012)) regular(0, xyz(0,0,0),dxdydz(16,16,1)) ) tile( ground(1011) regular(0, xyz(0,0,0),dxdydz(16,16,1)) ) // [2/3] tile( ground(1012) regular(1, xyz(0,0,0),dxdydz(16,16,1)) ) tile( ground(1011) regular(1, xyz(0,0,0),dxdydz(16,16,1)) ) // [4/5] tile( ground(1012) regular(2, xyz(0,0,0),dxdydz(16,16,1)) ) tile( ground(1011) regular(2, xyz(0,0,0),dxdydz(16,16,1)) ) // [6/7] tile( ground(1012) regular(3, xyz(0,0,0),dxdydz(16,16,1)) ) tile( ground(1011) regular(3, xyz(0,0,0),dxdydz(16,16,1)) ) // [8/9] tile( ground(1012) regular(4, xyz(0,0,0),dxdydz(16,16,1)) ) tile( ground(1011) regular(4, xyz(0,0,0),dxdydz(16,16,1)) ) // [10/11] tile( ground(1012) regular(5, xyz(0,0,0),dxdydz(16,16,1)) ) tile( ground(1011) regular(5, xyz(0,0,0),dxdydz(16,16,1)) ) // [12/13] tile( ground(1012) regular(6, xyz(0,0,0),dxdydz(16,16,1)) ) tile( ground(1011) regular(6, xyz(0,0,0),dxdydz(16,16,1)) ) // [14/15] tile( ground(1012) regular(7, xyz(0,0,0),dxdydz(16,16,1)) ) tile( ground(1011) regular(7, xyz(0,0,0),dxdydz(16,16,1)) ) )
Teraz, po skonfigurowaniu potrzebnej grafiki i ich układu kafli, będziemy musieli zbudować 'łańcuch kontroli', łącząc grafikę i układ z ID-stacji, a także obsługiwać animację kafli.
def(2) anim_frame( cbr(0) if(0) cbr(2) if(1) cbr(4) if(2) cbr(6) if(3) cbr(8) if(4) cbr(10) if(5) cbr(12) if(6) cbr(14) else ) def(3) anim_trigger( animcontrol(A_START) if(ARRIVE) // przybyć (arrive) animcontrol(A_STOP) if(LEAVE) // odejście (leave) animcontrol(A_NOP) else // do nothing ) def(4) callback( ref(2) if(CB_LAYOUT) ref(3) if(CB_ACONTROL) ref(1) else ) makestation(ANIMTEST, default(ref(4)) ) |