Skip to content

callbacksTut

extrazi edited this page Jun 25, 2023 · 17 revisions
original    original
EN     PL

m4nfo Tutorial

Callback tutorial

  • Introduction
  • Jak to działa
  • Jak zdefiniować callbacki
  • Przykłady
    • Przykład 1: używanie wywołań zwrotnych dźwięku (CB_SOUND)
    • Przykład 2: używanie wywołań zwrotnych dla ilości obciążenia, pojemności i dodatkowych sufiksów tekstowych
    • Przykład 3: używanie wywołań zwrotnych dotyczących długości wagonu i pojazdów przegubowych
    • Przykład 4: używanie 'callbacks' dotyczących zasilania, pojazdów przegubowych, 'dołączania' i dodatkowy tekst w menu zakupu
    • Przykład 5: użycie ogólnego wywołania zwrotnego, aby umożliwić sztucznej inteligencji zbudowanie odpowiednich stacji
Introduction

Od TTDPatch 2.0.1 alpha 11, możliwe jest użycie 'callbacków', w których newGRF mogą wpływać na działanie funkcji TTDPatch. Jest to o wiele bardziej wyrafinowane niż zwykłe używanie 'funkcji właściwości' do wybierania różnych ustawień, ponieważ wywołania zwrotne mogą wykorzystywać pełne możliwości różnych funkcji wydajnościowych , w tym randomizacji.

Jak to działa

Kiedy TTDPatch chce użyć wartości pewnych właściwości, może zapytać newGRF, jakiej wartości użyć, zamiast po prostu szukać jej w funkcji właściwości. Dzieje się tak, jeśli odpowiedni typ wywołania zwrotnego został ustawiony w funkcji callbacks() właściwości pojazdu. Następnie dzieje się co następuje:

  • TTDPatch ustawia bieżący identyfikator wywołania zwrotnego, zgodnie z tym, jaki to jest callback
  • Następnie TTDPatch rozpoczyna się od funkcji makevehicle() pojazdu i znajduje początkową funkcję wydajności do użycia
  • TTDPatch podąża następnie za łańcuchem funkcji wykonawczych
  • Wartość zwracana przez końcową funkcję wydajności jest używana jako wynik dla wywołania zwrotnego
Ponieważ wywołania zwrotne różnią się od zwykłej grafiki pojazdu, ostatnia funkcja w łańcuchu musi mieć 'wartość zwracaną przez wywołanie zwrotne' (tj. Z ustawionym bitem 15), co jest nieprawidłowe w przypadku zwykłej grafiki. Dlatego co najmniej jedna funkcja w łańcuchu musi być callback(), aby zdecydować, czy jest to wywołanie zwrotne, czy określenie grafiki.

Jak zdefiniować callbacki

Jest kilka rzeczy, które musisz zrobić, aby wywołania zwrotne działały:

  1. W razie potrzeby włącz oddzwanianie. W przypadku pojazdów ustaw wywołanie zwrotne w funkcji właściwości pojazdu, który powinien używać wywołań zwrotnych
  2. Ustaw wartość domyślną dla wartości, którą modyfikuje callback, np. użyj funkcji właściwości loadamount() podczas korzystania z funkcji zwrotnej kwoty obciążenia CB_LOAD
  3. Zdefiniuj funkcję makevehicle() dla pojazdu, jeśli jeszcze jej nie ma
  4. Dodaj funkcję callback() , która sprawdza typ wywołania zwrotnego. Zobacz listę callbacks pociągów, aby zobaczyć dostępne typy oddzwonień
  5. Ostatnia funkcja wydajności w łańcuchu musi zwrócić wynik wywołania zwrotnego w wywołaniu zwrotnym lub zwykły set-id, gdy nie jest w wywołaniu zwrotnym
  6. Upewnij się, że sprawdzenie "default" bloku funkcyjnego callback() (odpowiadającego nieznanym wywołaniom zwrotnym) wskazuje na zwykłą graficzną ikonkę zamiast funkcji, która zwraca wyniki wywołania zwrotnego, najlepiej używając tej samej funkcji lub sprite'a, co w przypadku nie wywołania zwrotnego . W ten sposób nieznane wywołania zwrotne nie będą zwracać prawidłowych, ale błędnych wyników.
Jak wyjaśniono w podręczniku użytkownika, wynikiem wywołania zwrotnego jest coś w rodzaju 'cbr(6)' (z "6" używaną jako wartość zwrotna wywołania zwrotnego), zamiast zwykłego odwołania do funkcji, które byłoby na przykład 'ref(4)'.

Przykłady

Należy pamiętać, że poniższe przykłady nie prowadzą do 100% kompletnych newGRFów, ale zamiast tego koncentrują się na najważniejszych cechach kodu. Np. W danych funkcjach właściwości pociągu należałoby dodać jeszcze więcej właściwości, aby uzyskać dobrze działający nowy GRF, lub w przypadku, gdy przykład opisuje szczegółowo tylko jeden pojazd, odniesienia do innych pojazdów, np. lokomotywy są podawane w formie symbolicznej ("xx", "nn"), zamiast implementować je szczegółowo i podawać prawidłowe identyfikatory pojazdów lub odniesienia do funkcji.

Przykład 1: używanie wywołań zwrotnych dźwięku (CB_SOUND)

Pierwszy przykład to bardzo prosta aplikacja. Ustawi nowe dźwięki dla lokomotywy za pomocą CB_SOUND . Nowe dźwięki będą dostarczane przez dwa pliki .wav za pomocą funkcji soundtable() . Typ zdarzenia dźwiękowego (w jakich okolicznościach należy odtworzyć określony dźwięk) jest zwracany przez funkcję soundevent() .

Przykład (używanie wywołań zwrotnych dźwięku):
 
 setfeature(_TRAIN)
 
 grf_init(GRF_TUT1, ...)
 
 // ustaw silnik (veh-ID 0), aby używał nowych 'sprites' i włączał dźwięku callback
 definevehicle(0,{},
 	newgraphics()
 	callbacks(CB_SOUND)
 )
 
 // zdefiniować pliki dźwiękowe
 soundtable(
 	defsnd(_DEPART, br38s.wav) 
 	defsnd(_TUNNEL, br38t.wav)
 )
 
 // idą tutaj sprite'y silnika
 spriteblock(
 	set(
 		sprite( ... )
 		sprite( ... )
 		sprite( ... )
 		sprite( ... )
 	)
 )
 
 def(0) spriteset(move(0),load(0)) // lokomotywa
 
 // funkcje wydajności silnika
 
 def(1) soundevent(
 	refsnd(_DEPART) if(SND_START)  // whistle: departure
 	refsnd(_TUNNEL) if(SND_TUNNEL) // whistle: in tunnel
 	cbfail() else		       // else CB fail
 )
 
 // przełączać się między callback i grafiką
 def(2) callback(
 	ref(1) if(CB_SOUND) // to dźwięku callback, ustaw dźwięk
 	ref(0)		    // grafiki
 )
 
 makevehicle(0,
 	default(ref(2))
 )

Przykład 2: używanie wywołań zwrotnych dla ilości obciążenia, pojemności i dodatkowych sufiksów tekstowych

Załóżmy, że chcesz zbudować wagony pasażerskie zarówno z pierwszą, jak i drugą klasą, z różnymi kolorami i pojemnością, wielkością załadunku i dodatkowymi sufiksami tekstowymi. Aby to zadziałało, będziemy potrzebować wywołań zwrotnych CB_LOAD (ilość ładunku), CB_RCAP (pojemność przywrócona) i CB_TSFX (wyświetlanie podtypu ładunku).

Ponadto użyjemy funkcji refitted() , aby móc celowo zmieniać barwy, wielkość załadunku i ładowność, nawet jeśli autokary przewożą tylko jeden rodzaj ładunku, a mianowicie „pasażerów”.

W kodzie źródłowym faktyczna "przebudowa" odbywa się poprzez wywołanie funkcji refitted(), która raportuje, ile razy pojazd był ponownie przystosowany do tego samego typu ładunku. W grze będą wtedy dwa wpisy w menu refit zawierające te sufiksy tekstowe wygenerowane przez funkcję defgrftext() . Mianowicie "pasażerowie (1 klasa)" i "pasażerowie (2 klasa)", z których można wybrać żądany typ autokaru. Podobnie, wielkość obciążenia i pojemność są również powiązane z funkcją ponownie zamontowaną() i zostaną odpowiednio zmienione.

 
 Przykład (używanie 'callbacks' dla ilości ładunku, 'refitted' pojemności i sufiksów tekstowych):
 
 setfeature(_TRAIN)
 
 grf_init(GRF_TUT2, ... )
 
 // zdefiniować dodatkowe sufiksy tekstowe
 defgrftext(0,ALL,
 	" (1st class)"
 	" (2nd class)"
 )
 
 // ustawić  wagon (veh-ID 27) na używanie nowych 'sprites',
 // i włącz wywołania zwrotne CB_LOAD, CB_RCAP, CB_TSFX 
 definevehicle(27,{},
 	newgraphics()
 	callbacks(CB_LOAD, CB_RCAP, CB_TSFX)
 )
 
 // idą tutaj sprite'y 'wagonu'
 spriteblock(
 	set(
 	// 4 sprites for 1st class coach
 		sprite(...)
 		sprite(...)
 		sprite(...)
 		sprite(...)
 	)
 	set(
 	// 4 sprites for 2nd class coach
 		sprite(...)
 		sprite(...)
 		sprite(...)
 		sprite(...)
 	)
 )
 
 def(0) spriteset(move(0),load(0)) // 1st class
 def(1) spriteset(move(1),load(1)) // 2nd class
 
 // funkcje wydajności silnika
 
 // kolejne 4 funkcje sprawdzają możliwości 'refitting'u':
 // [ 1 klasa, 48 pasażerów, ilość ładunku = 6] i 
 // [ 2 klasa, 56 pasażerów, ilość ładunku = 8]
 
 // ustawić wielkość obciążenia
 def(2) refitted(
 	cbr(6) if(0) // 1st class = 6/tick
 	cbr(8) else  // 2nd class = 8/tick
 )
 
 // ustawić 'refitted' pojemność
 def(3) refitted(
 	cbr(48) if(0) // 1st class = 48 pass
 	cbr(56) else  // 2nd class = 56 pass
 )
 
 // ustaw sufiksy tekstu
 def(4) refitted(
 	grftext(0) if(0) // "1-sza klasa"
 	grftext(1) else  // "2 klasa"
 )
 
 // zestaw barw
 def(5) refitted(
 	ref(0) if(0) // 1-sza klasa
 	ref(1) else  // 2 klasa
 )
 
 // przełączać się między callbackami a gałęzią grafiki
 def(6) callback(
 	ref(2) if(CB_LOAD) // set load amount
 	ref(3) if(CB_RCAP) // set refitted capacity
 	ref(4) if(CB_TSFX) // set text suffix
 	ref(5) else	   // graphics
 )
 
 makevehicle(27,
 	default(ref(6))
 )

Przykład 3: użycie wywołań zwrotnych 11 (długość wagonu) i 16 (silnik przegubowy)

Ten przykład pokaże, jak używać CB_ARTI do projektowania "pojazdów przegubowych", np. lokomotywy z przetargami. Skonfigurujemy dwie lokomotywy przy użyciu dwóch różnych ofert: <engine1> użyje standardowej krótkiej <tender1>, a <engine2> użyje jeszcze krótszej <tender2> poprzez zastosowanie CB_WLEN .

 Przykład (używanie callbacks w przypadku pojazdów przegubowych i długości pojazdu):
 
 setfeature(_TRAIN)
 
 grf_init(GRF_TUT3, ... )
 
 // ustaw ogólny tender (veh-ID 45) na używanie nowych 'sprites', 
 // włącz callback CB_WLEN
 definevehicle(45,{},
 	climate(INACTIVE)  // nie pojawiają się w menu zakupów
 	newgraphics()      // użyj nowych sprites 
 	callbacks(CB_WLEN) // włączyć callback do długości pojazdu
 	shortening(2)      // skróć o 25%
 )
 
 // tender sprites go here
 spriteblock(
 	set(
 		... // 8 sprites for tender1
 	)
 	set(
 		... // 8 sprites for tender2
 	)
 )
 
 def(240) spriteset(move(0),load(0)) // tender1 (0xF0)
 def(0) spriteset(move(1),load(1))   // tender2
 
 // tender2 (0xF1) is shorter
 def(241) callback(
 	cbr(3) if(CB_WLEN) // skrócić o 37.5%
 	ref(0) else	   // graphics
 )
 
 makevehicle(45,
 	default(ref(240)) // standard tender
 )
 
 // ustawienie dwóćh lokomotyw (00 and 01) na używanie nowych 'sprites' , 
 //  włącz callback CB_ARTI
 definevehicle(0,{},
 	newgraphics()      // użyj nowych sprites 
 	callbacks(CB_ARTI) // włączyć callback do pojazdu przegubowego
 )
 
 definevehicle(1,{},
 	newgraphics()      // use new sprites 
 	callbacks(CB_ARTI) // enable callback for articulated vehicle
 )
 
 // engine sprites go here
 spriteblock(
 	set(
 		... // 8 sprites for engine1
 	)
 	set(
 		... // 8 sprites for engine2
 	)
 )
 
 def(0) spriteset(move(0),load(0)) // engine1
 def(1) spriteset(move(1),load(1)) // engine2
 
 // <engine1> używa standardowego <tender1>
 // silnik jest przegubowy, więc pokaż silnik (0) lub tender (240)
 // w zależności od pozycji w składzie.
 // Ponieważ "multihead" jest dozwolone, potrzebujemy tutaj operacji modulo.
 def(2) veh_posrel(MOD2, 
 	ref(0) if(0)  // engine1
 	ref(240) else // tender1
 )
 
 def(3) articulated(
 	addveh(45) if(1) // dodanie tender (veh-ID 45)
 	ENDLIST else     // koniec pojazdu przegubowego
 )
 
 // Przełączanie się między callback a grafiką
 def(4) callback(
 	ref(3) if(CB_ARTI) // przegubowe callback
 	ref(2) else        // graphics
 )
 
 makevehicle(0,
 	default(ref(4)) // engine1 z tender1
 )
 
 
 // <engine2> używa krótszego <tender2>
 // silnik jest przegubowy, więc pokaż silnik (1) lub tender (241)
 def(2) veh_posrel(MOD2, 
 	ref(1) if(0)  // engine1
 	ref(241) else // tender1
 )
 
 // przełączać się między callback i grafiką
 def(4) callback(
 	ref(3) if(CB_ARTI) // przegubowe wywołanie zwrotne, takie samo jak dla <engine1></engine1>
 	ref(2) else        // graphics
 )
 
 makevehicle(1,
 	default(ref(4))       // engine2
 	override(45,ref(241)) // zastąp z tender2
 
 )
 

Przykład 4: używanie wywołań zwrotnych dla wagonów z napędem, pojazdów przegubowych, mocowania silnika i dodatkowego tekstu menu

Ten przykład wyjaśnia, jak używać CB_POWR (wagon z napędem), CB_ARTI (pojazd przegubowy), CB_ATAC (mocowanie silnika) i CB_TEXT (dodatkowy tekst w menu) do budowy czteroczęściowego EMU.

EMU składa się z tego samego bloku konstrukcyjnego, elektrycznego wagonu szynowego (poj-ID = 62). Ponadto należy zezwolić na połączenie trzech z tych czteroczęściowych EZT, tj. Pełny skład może zawierać łącznie 12 wagonów.

Ze względu na realizm, żadne „zagraniczne” pojazdy nie powinny być przyłączane do UGW. Uzyskuje się to poprzez sprawdzenie veh-ID przez veh_id() . Odpowiednie komunikaty o błędach zostaną wygenerowane, jeśli coś jest nie tak z liczbą lub typem dodanych pojazdów.

Prośba odnotowania, że CB_ATAC i CB_TEXT nie potrzebują być wprowadzane w właściwości funkcji callbacks() .

Ponadto pokazano, jak utworzyć wyraźną pozycję menu dla takiej UGW. Aby to zadziałało, potrzebujemy dodatkowego sprite'a przedstawiającego nie pojedynczy wagon, ale całą czteroczęściową EMU. Ponieważ ten 'sprite' będzie używany tylko w menu kupowania, odpowiedni blok 'sprites' potrzebuje tylko tego pojedynczego 'sprite' dla kierunku poziomego. Wszystkie inne kierunki nie są potrzebne, dlatego nie musimy uwzględniać dla nich sprite'ów.

Ponadto łańcuch funkcji dla pozycji menu wymaga odniesień do wywołań zwrotnych CB_ARTI i CB_TEXT. Ten ostatni służy do umieszczania tekstu dodatkowych informacji we wpisie menu, a CB_ARTI jest potrzebne, aby pojemność czteroczęściowej EMU była poprawnie wyświetlana w menu zakupów.

Przykład (używanie callbacks dla wagonów z napędem, pojazdów przegubowych, 'mocowania' silnika, i dodatkowego tekstu menu):
 setfeature(_TRAIN)
 
 grf_init(GRF_TUT4, ... )
 
 // komunikaty o błędach 'załączenie silnika' 
 define(ATT_CARBADNUM,0x00)
 define(ATT_CARBADTYPE,0x01)
 
 defgrftext(ATT_CARBADNUM,ALL,
 	" (wrong number of cars)",
 	" (wrong type of car)"
 )
 
 // dodatkowy tekst do menu
 define(TLH_4PARTEMU,0x02)
 defgrftext(TLH_4PARTEMU,ALL,
 	CRLF T_LORANGE "4-part EMU for commuter service."
 	" (Links max 12 parts)"
 )
 
 // ustawić wagon (veh-ID 98) na używanie nowych 'sprites', 
 // umożliwia wywołania zwrotne do wagonów z napędem i pojazdów przegubowych
 define(_BR425,98)
 definevehicle(_BR425,{},
 	newgraphics()
 	enginetype(ELECTRIC)
 	callbacks(CB_POWR, CB_ARTI)
 )
 
 //----------------------------------------------------------
 // the "train"
 //----------------------------------------------------------
 
 //  wszystkie sprite'y wagonów są tutaj
 spriteblock(
 	set(
 		sprite( ... ) // 8 sprites dla 1-y wagon
 	)
 	set(
 		sprite( ... ) // 8 sprites  2-i -"-
 	)
 	set(
 		sprite( ... ) // 8 sprites  3 -"-
 	)
 	set(
 		sprite( ... ) // 8 sprites  4y -"-
 	)
 )
 
 // użyj powyższych zestawów  sprites
 def(0) spriteset(move(0),load(0)) // 1 wagon
 def(1) spriteset(move(1),load(1)) // 2  -"-
 def(2) spriteset(move(2),load(2)) // 3  -"-
 def(3) spriteset(move(3),load(3)) // 4  -"-
 
 // określić, w jakim samochodzie się znajdujemy. Możemy połączyć maksymalnie cztery
 // EMU w składzie, więc użyj funkcji modulo-4.
 def(2) veh_posrel(MOD4, 
 	ref(3) if(3) // 4th car
 	ref(2) if(2) // 3rd car
 	ref(1) if(1) // 2nd car
 	ref(0) else  // 1st car
 )
 
 // ustawić callback dla pojazdu przegubowego
 def(5) articulated(
 	addveh(_BR425) if(1 .. 3) // 3 dodatkowe części tego ID-pojazdu
 	ENDLIST else		  // koniec pojazdu przegubowego
 )
 
 // ustawić callback do podłączenia silnika
 // zezwalaj tylko na 3 * EMU (= 12 wagonów)
 def(6) veh_num(
 	engine(
 		attach(ATT_OK) if(0 .. 9)  // pozwalają na dodanie dodatkowych 8 wagonów
 		attach(ATT_CARBADNUM) else // błąd: "zła liczba wagonów"
 	)
 )
 
 // pozwolić tylko EMU na przyłączenie się, nic więcej
 def(7) veh_id(
 	ref(6) if(_BR425)	    // allow, check total number of cars
 	attach(ATT_CARBADTYPE) else // error: "wrong type of car"
 )
 
 // tylko wagon 1 i jeśli istnieją, 5 i 9 powinny iskrzeć
 def(8) veh_posabs(FRONT, 
 	effect(electric(4)) if(1,5,9) // iskra
 	ref(0) else		      // brak iskier
 )
 
 // przełączać się między callback i grafiką
 def(9) callback(
 	ref(5) if(CB_ARTI) // pojazd przegubowy
 	ref(7) if(CB_ATAC) // silnik podłączyć
 	ref(8) if(CB_POWR) // moc i efekty
 	ref(4) else	   // graphics
 )
 
 //----------------------------------------------------------
 // pozycja menu
 //----------------------------------------------------------
 
 spriteblock(
 	set(
 		sprite(emu.pcx 226 120 01 15 91 -27 -11)
 	)
 )
 
 def(0) spriteset(move(0),load(0)) // menu pic
 
 // przełączać się między callback i grafiką
 def(1) callback(
 	ref(5) if(CB_ARTI)     // (do obliczenia pojemności)
 	grftext() if (CB_TEXT) // show additional text in menu
 	ref(0) else	       // graphics
 )
 
 makevehicle(_BR425,
 	link(ref(1),MENU) // menu entry
 	default(ref(9))   // vehicle
 )
 

Przykład 5: użycie ogólnego wywołania zwrotnego, aby umożliwić AI zbudowanie odpowiednich stacji

W oryginalnym TTD AI była zakodowana na stałe. W przypadku pojazdów miał stałą listę dla każdego rodzaju ładunku, a dla stacji używał po prostu jednego z 4 możliwych typów stacji TTD.

Po raz pierwszy TTDPatch zaimplementował interfejs między AI i newGRF, wprowadzając ogólne wywołanie zwrotne ("Wybór budowy/zakupu AI"). Jest to wymagane do podejmowania różnych decyzji, gdy sztuczna inteligencja konstruuje nową trasę. Dzięki temu wywołaniu zwrotnemu stało się możliwe uzależnienie wyboru AI od branży źródłowej i docelowej, a także odległości usług.

W tym przykładzie pokazano, jak nauczyć sztuczną inteligencję budowania stacji z 1 lub 2 platformami w zależności od przewożonego ładunku, bieżącego roku i liczby mieszkańców miasta, w którym stacja ma zostać zbudowana.

W m4nfo, ogólne wywołanie zwrotne nazywa się CB_AISELECT , zwraca ID-stacji, która ma być zbudowana (przez funkcję cbr() ), najprawdopodobniej opracowaną po ocenie pewnych zmiennych, patrz przykładowy kod.

Prośba odnotowania na specjalną postać funkcji makestation() , która w ogóle nie określa żadnego identyfikatora stacji. Tworzy to ogólną definicję specyficzną dla funkcji, niezwiązaną z żadną konkretną funkcją, która jest używana na potrzeby ogólnego wywołania zwrotnego.

Prośba odnotowania również , że ten przykład kodu jest częścią zestawu NewStations i jako taki odnosi się do typów stacji ('DACHY', ŁAWKI, 'PŁASKIE', ...) zdefiniowane w tym zestawie.

Również prośba odnotowania, że w OpenTTD SI jest implementowana przez niezależne moduły, więc potrzebujesz takiego, który implementuje również stacje budowlane, a nie tylko pojazdy.

Przykład (niech SI buduje stacje):
 //------------------------------------------------------------------
 // AI platforms                   
 //------------------------------------------------------------------
 
 // Losuj za pomocą tick silnika anim_counter():
 // trzeba przesunąć w prawo o 3 bity, ponieważ jeden gracz jest przetwarzany
 // każdy tik, więc mod 8 będzie zawsze taki sam dla każdego gracza
 
 // Pick n*1 station, <1950
 def(1) anim_counter(shiftmask(3,7),
 	cbr(ROOFS) if(0 .. 2)	// roofs
 	cbr(BENCHES) if(3 .. 4) // ławki
 	cbr(SHALL) else		// mała hala
 )
 
 // Pick n*1 station, >1950
 def(2) anim_counter(shiftmask(3,7),
 	cbr(ROOFS) if(0 .. 1)	// roofs
 	cbr(BENCHES) if(2 .. 3) // benches
 	cbr(SHALL) if(4 .. 5)	// small hall
 	cbr(PFRONT) if(6)	// carpark front
 	cbr(PBACK) else		// 'parking' tył
 )
 
 // Wybierz stację n*1 w zależności od roku
 def(3) year(
 	ref(1) if(<1950)
 	ref(2) else
 )
 
 def(1) townpopulation(
 	cbr(FLATROOF) if(<800) // budował "płaskie dachy" w małych miejscowościach-->
 	cbr(GLASS)	       // built modern "glass roofs" for larger towns
 )
 
 // Pick n*2 station depending on year
 def(4) year(
 	cbr(ROOFS) if(<1960)	       // build "roofs"
 	cbr(FLATROOF) if(1960 .. 1979) // build "flat roofs"
 	ref(1) else		       // check town population
 )
 
 // Sprawdź liczbę platform
 def(5) AI_stationwidth(
 	ref(3) if(1)  // 1-track platform
 	ref(4) if(2)  // 2-track platform
 	cbfail() else // obsługiwane tylko 1 i 2 tory
 )
 
 // Check passenger/mail service
 def(6) AI_cargo(
 	ref(5) if(PASS, MAIL)
 	cbfail() else // fracht nie jest obsługiwany!
 )
 
 // Check callback typ:
 // zwraca nieprawidłowy wynik dla braku wywołania zwrotnego lub wywołania zwrotnego innego niż 18
 def(7) callback(
 	ref(6) if(CB_AISELECT)  // AI construction
 	cbfail(0) if(1 .. 0xFF) // nieprawidłowy CB
 	NOTAVAILABLE else	// no callback
 )
 
 // zdefiniować ogólne wywołanie zwrotne stacji
 makestation(default(ref(7)))