-
Notifications
You must be signed in to change notification settings - Fork 0
callbacksTut
EN PL |
- 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
Jak zdefiniować callbacki |
Jest kilka rzeczy, które musisz zrobić, aby wywołania zwrotne działały:
- 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
- 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
- Zdefiniuj funkcję makevehicle() dla pojazdu, jeśli jeszcze jej nie ma
- Dodaj funkcję callback() , która sprawdza typ wywołania zwrotnego. Zobacz listę callbacks pociągów, aby zobaczyć dostępne typy oddzwonień
- 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
- 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.
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)))