Drezyna WM-15A - dodanie logiki działania...
Zaprezentowana w poprzednim poście drezyna jeździ i wozi towary, jednak jej zachowanie nie do końca odpowiada rzeczywistości...
Pierwszym mankamentem jest to, że drezyna oraz jej przyczepka są "widziane" przez program jako zwykła lokomotywa i wagon. Można więc je łączyć w długie składy, w dodatku wymieszane z innymi wagonami. Drugim problemem jest niewłaściwa ilość przewożonych towarów, wynikająca z użycia przez OpenTTD domyślnych przeliczników sztuk na tony i odwrotnie.
Oba powyższe problemy można rozwiązać stosując mechanizm tzw. callback-ów i switch-y, czyli pewnego rodzaju funkcji, za pośrednictwem których gra "dowiaduje się", jak ma wyglądać i zachowywać się nasz pojazd w pewnych określonych przypadkach.
Ograniczenie długości i składu pociągu
Problem mieszanych i za długich składów pociągów można rozwiązać definiując w kodzie NML następujące switch-e:
...które należy następnie podpiąć pod odpowiednie callback-i w sekcji graphics projektowanej drezyny:
Wyjaśnię teraz, jak to działa. Callback can_attach_wagon jest wywoływany przez OTTD za każdym razem, gdy gracz w oknie zajezdni próbuje dołączyć wagon do lokomotywy. Wywołanie tego callback-a powoduje uruchomienie switch-a switch_wm15a_can_attach, który sprawdza identyfikator dołączanego wagonu (vehicle_type_id); Jeśli dołączanym wagonem jest przyczepa WM15, wszystko będzie OK. W przeciwnym wypadku zwrócony zostanie komunikat o błędzie:
![[Obrazek: 721blad_typu.png]](https://openttd-polska.pl/uploads/other/721blad_typu.png)
Drugi z użytych callback-ów (start_stop) jest wywoływany przez OTTD m.in. w momencie, gdy gracz próbuje wypuścić pociąg z zajezdni. W powyższym przykładzie uruchamiany jest switch switch_wm15a_start_stop, który sprawdza długość pociągu (num_vehs_in_consist). Jeśli długość mieści się w zakresie 1-2 pojazdów, pociąg zostanie wypuszczany. W przeciwnym wypadku zwrócony zostanie komunikat błędu:
![[Obrazek: 833blad_dlugosci.png]](https://openttd-polska.pl/uploads/other/833blad_dlugosci.png)
Ustawienie właściwej pojemności
Problem niewłaściwej ilości wożonych towarów wynika z domyślnego mechanizmu przeliczania przez OTTD sztuk na tony i odwrotnie. Parametr cargo_capacity, określający pojemność wagonu, odnosi się bowiem zawsze do pierwszego w kolejności typu wożonego ładunku. W przypadku drezyny WM-15A definicja:
...oznacza więc 15 pasażerów, a nie 15 ton ładunku.
W momencie przebudowy drezyny do wożenia innych towarów, gra przeliczy pojemność wagonu z 15 pasażerów na...zaledwie 7 ton ładunku. Tymczasem prawdziwa WM-15A może przewieźć aż 15 ton ładunku, lecz pasażerów w kabinie zmieści się zaledwie 7-miu, czyli zupełnie odwrotnie niż policzyła gra...
Aby temu zaradzić, należy poinformować grę o tym, jak ma traktować poszczególne rodzaje ładunku. W tym celu należy jednak już operować identyfikatorami konkretnych towarów, a nie jak do tej pory - ogólnymi klasami towarów. Wynika to z faktu, że nawet towary z jednej klasy mogą mieć różne jednostki miary.
Aby wprowadzić indywidualną obsługę towarów, najpierw trzeba zdefiniować tzw. tabelę towarów (cargotable), w której należy wyliczyć wszystkie towary, które będą traktowane przez nasz NewGRF w szczególny sposób (pełną listę identyfikatorów towarów można znaleźć tutaj: http://newgrf-specs.tt-wiki.net/wiki/Car...rgo_Labels ):
Następnie należy zdefiniować switch, który na podstawie informacji o aktualnie przewożonym ładunku (cargo_type_in_veh) będzie zwracał poprawną pojemność pojazdu. W przypadku drezyny będzie to 7 pasażerów(lub turystów), 30 paczek poczty lub 15 sztuk/skrzyń/ton dowolnego innego towaru:
Aby właściwe wyliczanie pojemności drezyny działało prawidłowo, należy jeszcze podpiąć napisany wyżej switch pod odpowiedni callback w sekcji graphics naszej drezyny:
Analogiczne zmiany w obsłudze towarów należy również wprowadzić dla przyczepy PMW-15.
Kompletny kod NewGRF
Poniżej zamieszczam treść plików, które zmieniły się w wyniku wprowadzenia opisanych zmian:
lang/english.lng
lang/polish.lng
wm15a.nml
Zaprezentowana w poprzednim poście drezyna jeździ i wozi towary, jednak jej zachowanie nie do końca odpowiada rzeczywistości...

Pierwszym mankamentem jest to, że drezyna oraz jej przyczepka są "widziane" przez program jako zwykła lokomotywa i wagon. Można więc je łączyć w długie składy, w dodatku wymieszane z innymi wagonami. Drugim problemem jest niewłaściwa ilość przewożonych towarów, wynikająca z użycia przez OpenTTD domyślnych przeliczników sztuk na tony i odwrotnie.
Oba powyższe problemy można rozwiązać stosując mechanizm tzw. callback-ów i switch-y, czyli pewnego rodzaju funkcji, za pośrednictwem których gra "dowiaduje się", jak ma wyglądać i zachowywać się nasz pojazd w pewnych określonych przypadkach.
Ograniczenie długości i składu pociągu
Problem mieszanych i za długich składów pociągów można rozwiązać definiując w kodzie NML następujące switch-e:
Kod:
switch(FEAT_TRAINS, SELF, switch_wm15a_can_attach, vehicle_type_id) {
item_pwm15: return CB_RESULT_ATTACH_ALLOW;
return string(STR_WM15A_ATTACH_DISALLOW);
}
switch (FEAT_TRAINS, SELF, switch_wm15a_start_stop, num_vehs_in_consist) {
1..2: return CB_RESULT_NO_TEXT;
return string(STR_WM15A_CANNOT_START);
}...które należy następnie podpiąć pod odpowiednie callback-i w sekcji graphics projektowanej drezyny:
Kod:
graphics {
purchase: spriteset_wm15a_purchase;
default: spriteset_wm15a_empty;
can_attach_wagon: switch_wm15a_can_attach; // <- dodane
start_stop: switch_wm15a_start_stop; // <- dodane
}Wyjaśnię teraz, jak to działa. Callback can_attach_wagon jest wywoływany przez OTTD za każdym razem, gdy gracz w oknie zajezdni próbuje dołączyć wagon do lokomotywy. Wywołanie tego callback-a powoduje uruchomienie switch-a switch_wm15a_can_attach, który sprawdza identyfikator dołączanego wagonu (vehicle_type_id); Jeśli dołączanym wagonem jest przyczepa WM15, wszystko będzie OK. W przeciwnym wypadku zwrócony zostanie komunikat o błędzie:
![[Obrazek: 721blad_typu.png]](https://openttd-polska.pl/uploads/other/721blad_typu.png)
Drugi z użytych callback-ów (start_stop) jest wywoływany przez OTTD m.in. w momencie, gdy gracz próbuje wypuścić pociąg z zajezdni. W powyższym przykładzie uruchamiany jest switch switch_wm15a_start_stop, który sprawdza długość pociągu (num_vehs_in_consist). Jeśli długość mieści się w zakresie 1-2 pojazdów, pociąg zostanie wypuszczany. W przeciwnym wypadku zwrócony zostanie komunikat błędu:
![[Obrazek: 833blad_dlugosci.png]](https://openttd-polska.pl/uploads/other/833blad_dlugosci.png)
Ustawienie właściwej pojemności
Problem niewłaściwej ilości wożonych towarów wynika z domyślnego mechanizmu przeliczania przez OTTD sztuk na tony i odwrotnie. Parametr cargo_capacity, określający pojemność wagonu, odnosi się bowiem zawsze do pierwszego w kolejności typu wożonego ładunku. W przypadku drezyny WM-15A definicja:
Kod:
refittable_cargo_classes: bitmask(CC_PASSENGERS, CC_MAIL, CC_EXPRESS, CC_PIECE_GOODS);
...
cargo_capacity: 15;W momencie przebudowy drezyny do wożenia innych towarów, gra przeliczy pojemność wagonu z 15 pasażerów na...zaledwie 7 ton ładunku. Tymczasem prawdziwa WM-15A może przewieźć aż 15 ton ładunku, lecz pasażerów w kabinie zmieści się zaledwie 7-miu, czyli zupełnie odwrotnie niż policzyła gra...
Aby temu zaradzić, należy poinformować grę o tym, jak ma traktować poszczególne rodzaje ładunku. W tym celu należy jednak już operować identyfikatorami konkretnych towarów, a nie jak do tej pory - ogólnymi klasami towarów. Wynika to z faktu, że nawet towary z jednej klasy mogą mieć różne jednostki miary.
Aby wprowadzić indywidualną obsługę towarów, najpierw trzeba zdefiniować tzw. tabelę towarów (cargotable), w której należy wyliczyć wszystkie towary, które będą traktowane przez nasz NewGRF w szczególny sposób (pełną listę identyfikatorów towarów można znaleźć tutaj: http://newgrf-specs.tt-wiki.net/wiki/Car...rgo_Labels ):
Kod:
cargotable {
PASS, TOUR, MAIL
}Następnie należy zdefiniować switch, który na podstawie informacji o aktualnie przewożonym ładunku (cargo_type_in_veh) będzie zwracał poprawną pojemność pojazdu. W przypadku drezyny będzie to 7 pasażerów(lub turystów), 30 paczek poczty lub 15 sztuk/skrzyń/ton dowolnego innego towaru:
Kod:
switch (FEAT_TRAINS, SELF, switch_wm15a_capacity, cargo_type_in_veh) {
PASS..TOUR: return 7;
MAIL: return 30;
return 15;
}Aby właściwe wyliczanie pojemności drezyny działało prawidłowo, należy jeszcze podpiąć napisany wyżej switch pod odpowiedni callback w sekcji graphics naszej drezyny:
Kod:
graphics {
purchase: spriteset_wm15a_purchase;
default: spriteset_wm15a_empty;
can_attach_wagon: switch_wm15a_can_attach;
start_stop: switch_wm15a_start_stop;
cargo_capacity: switch_wm15a_capacity; // <- dodane
}Analogiczne zmiany w obsłudze towarów należy również wprowadzić dla przyczepy PMW-15.
Kompletny kod NewGRF
Poniżej zamieszczam treść plików, które zmieniły się w wyniku wprowadzenia opisanych zmian:
lang/english.lng
Kod:
##grflangid 0x01
# This is the English language file
# GRF name and description
STR_GRF_NAME :{TITLE} {VERSION}
STR_GRF_DESCRIPTION :{TITLE} - the most known polish trolley.{}{COPYRIGHT}2011 Tadeusz Domagalski{}License: GPL v2
STR_WM15A_NAME :Trolley WM-15A (Diesel)
STR_PWM15_NAME :Trailer PWM-15
STR_WM15A_CANNOT_START :Train too long! Only 1 carriage allowed.
STR_WM15A_ATTACH_DISALLOW :Only PWM-15 can be attached to WM-15A.lang/polish.lng
Kod:
##grflangid 0x30
# Polska wersja językowa
# Nazwa GRF oraz opis
STR_GRF_NAME :{TITLE} {VERSION}
STR_GRF_DESCRIPTION :{TITLE} - popularna polska drezyna.{}{COPYRIGHT}2011 Tadeusz Domagalski{}License: GPL v2
STR_WM15A_NAME :Drezyna WM-15A (Diesel)
STR_PWM15_NAME :Przyczepa PWM-15
STR_WM15A_CANNOT_START :Pociąg jest za długi! Drezyna WM-15A może uciągnąć tylko 1 wagon.
STR_WM15A_ATTACH_DISALLOW :Drezyna WM-15A może współpracować tylko z przyczepą PWM-15.wm15a.nml
Kod:
grf {
grfid: "TD\01\01";
name: string(STR_GRF_NAME);
desc: string(STR_GRF_DESCRIPTION);
version: 0;
min_compatible_version: 0;
}
/* graphics definition */
template template_sprite_train(x, y) {
// [left_x, upper_y, width, height, offset_x, offset_y]
[x, y, 12, 28, -5, -16]
[x+ 16, y, 26, 28, -17, -18]
[x+ 46, y, 36, 20, -17, -14]
[x+ 86, y, 26, 28, -7, -18]
[x+120, y, 12, 28, -5, -16]
[x+136, y, 26, 28, -17, -18]
[x+166, y, 36, 20, -17, -14]
[x+206, y, 26, 28, -7, -18]
}
template template_sprite_purchase(x, y) {
// [left_x, upper_y, width, height, offset_x, offset_y]
[x, y, 50, 12, -25, -8]
}
train_width_32_px = 1;
traininfo_y_offset = 2;
/* empty sprites */
spriteset(spriteset_wm15a_empty, "gfx/wm15a.png") {
template_sprite_train(4, 20)
}
spriteset(spriteset_wm15a_purchase, "gfx/wm15a.png") {
template_sprite_purchase(4, 100)
}
spriteset(spriteset_pwm15_empty, "gfx/wm15a.png") {
template_sprite_train(4, 60)
}
spriteset(spriteset_pwm15_purchase, "gfx/wm15a.png") {
template_sprite_purchase(4, 120)
}
/* cargos */
cargotable {
PASS, TOUR, MAIL
}
/* switches */
switch(FEAT_TRAINS, SELF, switch_wm15a_can_attach, vehicle_type_id) {
item_pwm15: return CB_RESULT_ATTACH_ALLOW;
return string(STR_WM15A_ATTACH_DISALLOW);
}
switch (FEAT_TRAINS, SELF, switch_wm15a_start_stop, num_vehs_in_consist) {
1..2: return CB_RESULT_NO_TEXT;
return string(STR_WM15A_CANNOT_START);
}
switch (FEAT_TRAINS, SELF, switch_wm15a_capacity, cargo_type_in_veh) {
PASS..TOUR: return 7;
MAIL: return 30;
return 15;
}switch (FEAT_TRAINS, SELF, switch_pwm15_capacity, cargo_type_in_veh) {
MAIL: return 30;
return 15;
}
/* Define the actual train */
item(FEAT_TRAINS, item_wm15a) {
property {
/* common properties */
name: string(STR_WM15A_NAME);
climates_available: bitmask(CLIMATE_TEMPERATE, CLIMATE_ARCTIC);
introduction_date: date(1977, 1, 1);
model_life: VEHICLE_NEVER_EXPIRES;
vehicle_life: 20;
reliability_decay: 20;
refittable_cargo_classes: bitmask(CC_PASSENGERS, CC_MAIL, CC_EXPRESS, CC_PIECE_GOODS);
non_refittable_cargo_classes: bitmask(CC_REFRIGERATED, CC_LIQUID);
cargo_allow_refit: [];
cargo_disallow_refit: [];
loading_speed: 5;
cost_factor: 9;
running_cost_factor: 18;
/* train properties */
sprite_id: SPRITE_ID_NEW_TRAIN;
speed: 80 km/h;
misc_flags: bitmask();
refit_cost: 0;
track_type: RAIL;
ai_special_flag: AI_FLAG_CARGO;
power: 147 kW;
running_cost_base: RUNNING_COST_DIESEL;
dual_headed: 0;
cargo_capacity: 15;
weight: 20 ton;
ai_engine_rank: 0; // not intended to be used by the ai
engine_class: ENGINE_CLASS_DIESEL;
extra_power_per_wagon: 0 kW;
tractive_effort_coefficient: 0.3;
air_drag_coefficient: 0.1;
length: 8;
extra_weight_per_wagon: 0;
visual_effect_and_powered: visual_effect_and_powered(VISUAL_EFFECT_DIESEL, -2, DISABLE_WAGON_POWER);
bitmask_vehicle_info: 0;
}
graphics {
default: spriteset_wm15a_empty;
purchase: spriteset_wm15a_purchase;
can_attach_wagon: switch_wm15a_can_attach;
start_stop: switch_wm15a_start_stop;
cargo_capacity: switch_wm15a_capacity;
}
}
item(FEAT_TRAINS, item_pwm15) {
property {
/* common properties */
name: string(STR_PWM15_NAME);
climates_available: bitmask(CLIMATE_TEMPERATE, CLIMATE_ARCTIC);
introduction_date: date(1977, 1, 1);
model_life: VEHICLE_NEVER_EXPIRES;
vehicle_life: 20;
reliability_decay: 20;
refittable_cargo_classes: bitmask(CC_MAIL, CC_EXPRESS, CC_PIECE_GOODS);
non_refittable_cargo_classes: bitmask(CC_REFRIGERATED, CC_LIQUID);
cargo_allow_refit: [];
cargo_disallow_refit: [];
loading_speed: 5;
cost_factor: 130;
running_cost_factor: 1;
/* train properties */
sprite_id: SPRITE_ID_NEW_TRAIN;
speed: 80 km/h;
misc_flags: bitmask();
refit_cost: 0;
track_type: RAIL;
ai_special_flag: AI_FLAG_CARGO;
power: 0;
running_cost_base: RUNNING_COST_DIESEL;
cargo_capacity: 15;
weight: 12 ton;
ai_engine_rank: 0; // not intended to be used by the ai
extra_power_per_wagon: 0 kW;
tractive_effort_coefficient: 0.3;
air_drag_coefficient: 0.1;
length: 6;
extra_weight_per_wagon: 0;
visual_effect_and_powered: visual_effect_and_powered(VISUAL_EFFECT_DISABLE, 0, DISABLE_WAGON_POWER);
extra_weight_per_wagon: 0 ton;
bitmask_vehicle_info: 0;
}
graphics {
default: spriteset_pwm15_empty;
purchase: spriteset_pwm15_purchase;
cargo_capacity: switch_pwm15_capacity;
}
}![OpenTTD #Polska - Polskie forum gry OpenTTD [ARCHIWUM] OpenTTD #Polska - Polskie forum gry OpenTTD [ARCHIWUM]](https://forum.openttd.pl/images/logo.png)
