Parametry parowozu
Następnym krokiem w projektowaniu parowozu jest zaprogramowanie jego parametrów. Struktura tych parametrów wygląda podobnie jak w przypadku poprzedniej drezyny WM-15A:
Znaczenie większości parametrów jest opisane w dokumentacji, zamieszczonej na OpenTTD Wiki. Niektóre z nich wymagają jednak dokładniejszego wytłumaczenia:
speed (prędkość maksymalna) - niby wszystko jasne, lecz OTTD wprowadza szereg zaokrągleń w trakcie dokonywanych przeliczeń, przez co prędkość widoczna w grze czasem odbiega dość mocno od tej zadanej w GRF-ie. Dlatego należy ją doświadczalnie zwiększyć o 1-3 km/h, aby uzyskać wynik jak najbardziej zbliżony do żądanego.
weight (ciężar) - w przypadku pojazdu przegubowego jest to masa całego pojazdu. Dla Pt31 podana jest więc suma ciężaru lokomotywy (106 ton) oraz jej węglarki (67 ton).
tractive_effort_coefficient (współczynnik maksymalnej siły pociągowej) - współczynnik określający jaka część ciężaru pojazdu przekłada się na jego siłę pociągową. W przypadku pojazdów szynowych przyjmuje się 0.3 (30%). Dla parowozu współczynnik ten musi być jeszcze skorygowany ze względu na fakt, że nie wszystkie osie parowozu są napędzane. W przypadku Pt31 nacisk na jedną oś napędową wynosi 18,3 tony. Po przemnożeniu przez 4 osie mamy "zaledwie" ok. 74 ton masy czynnej w porównaniu ze 173 tonami masy całkowitej.
Dodanie obsługi przegubowości
Najistotniejszym etapem tworzenia pojazdu przegubowego jest napisanie odpowiednich funkcji (switch-y), odpowiedzialnych za realizację efektów przegubowości:
... oraz podpięcie ich pod odpowiednie callback-i w sekcji graphics pojazdu:
Callback-iem decydującym o istnieniu przegubowości jest callback articuladed_part. Podpiety pod niego swith switch_pt31_articulated jest wywoływany w trakcie tworzenia pojazdu wielokrotnie, w celu określenia identyfikatorów dodatkowych członów pojazdu. Za każdym wywołaniem swoitch-a w jego parametrze extra_callback_info1 znajduje się numer kolejnego członu pojazdu. Zwracaną przez switch wartością powinien być identyfikator tego kolejnego członu lub wartość 0xFF, oznaczająca koniec pojazdu.
W naszym przypadku zarówno lokomotywa, jak i jej węglarka, powinny mieć dokładnie ten sam identyfikator (parowóz jest pojazdem nierozdzielnym), dlatego na pytanie o drugi człon pojazdu (extra_callback_info1 = 1) zwracany jest również identyfikator item_pt31.
Drugi ze zdefiniowanych switch-y, switch_pt31_graphics odpowiada za właściwą wizualizację parowozu jako pojazdu przegubowego. Konieczność stworzenia tego switcha wynika z faktu, że wszystkie człony parowozu mają ten sam identyfikator. Musimy więc poinformowac grę, kiedy w ramach tego samego identyfikatora item_pt31 ma wyświetlić lokomotywę, a kiedy węglarkę.
Decyzja ta jest podejmowana na podstawie parametru position_in_vehid_chain, który określa ni mniej, ni więcej, tylko kolejną pozycję danego członu w łańcuchu pojazdów o tym samym identyfikatorze. W pokazanym przypadku wartość ta jest jeszcze poddana operacji modulo 2, aby właściwe sprite-y były wyświetlane także dla kolejnych lokomotyw w składzie, jadących w tzw. "trakcji wielokrotnej".
Trzeci switch, switch_pt31_visual_effect pełni bardzo podobną rolę, co poprzedni switch, lecz dotyczy "efektów specjalnych" wyświetlanych przez grę. Zadaniem tego switcha jest spowodowanie, że dym z komina będzie generowany jedynie przez lokomotywę. Węglarka będzie miała nieaktywne wszelkie efekty.
Kompletny kod NewGRF
Poniżej zamieszczam pełną treść plików, niezbędnych do skompilowania dodatku:
custom_tags.txt
lang/english.lng
lang/polish.lng
pt31.nml
Na koniec przedstawiam zrzut ekranu, przedstawiający różne przykłady szynowych pojazdów przegubowych pod OTTD
:
Następnym krokiem w projektowaniu parowozu jest zaprogramowanie jego parametrów. Struktura tych parametrów wygląda podobnie jak w przypadku poprzedniej drezyny WM-15A:
Kod:
/* Define the actual train */
item(FEAT_TRAINS, item_pt31) {
property {
/* common properties */
name: string(STR_PT31_NAME);
climates_available: bitmask(CLIMATE_TEMPERATE, CLIMATE_ARCTIC);
introduction_date: date(1931, 1, 1);
model_life: VEHICLE_NEVER_EXPIRES;
vehicle_life: 30;
reliability_decay: 20;
refittable_cargo_classes: bitmask(CC_PASSENGERS);
non_refittable_cargo_classes: bitmask();
refittable_cargo_types: bitmask();
loading_speed: 5;
cost_factor: 18;
running_cost_factor: 122;
/* train properties */
sprite_id: SPRITE_ID_NEW_TRAIN;
speed: 111 km/h;
misc_flags: bitmask();
refit_cost: 0;
track_type: RAIL;
ai_special_flag: AI_FLAG_PASSENGER;
power: 1471 kW;
running_cost_base: RUNNING_COST_STEAM;
dual_headed: 0;
cargo_capacity: 0;
weight: 173 ton; // 106+67 ton
ai_engine_rank: 0; // not intended to be used by the ai
engine_class: ENGINE_CLASS_STEAM;
extra_power_per_wagon: 0 kW;
tractive_effort_coefficient: 0.3*74/173;
air_drag_coefficient: 0.07;
shorten_vehicle: SHORTEN_TO_8_8;
extra_weight_per_wagon: 0;
visual_effect_and_powered: visual_effect_and_powered(VISUAL_EFFECT_DEFAULT, 0, DISABLE_WAGON_POWER);
extra_weight_per_wagon: 0 ton;
bitmask_vehicle_info: 0;
}
graphics {
purchase: spriteset_pt31_purchase;
default: spriteset_pt31; // <- tymczasowo
}
}Znaczenie większości parametrów jest opisane w dokumentacji, zamieszczonej na OpenTTD Wiki. Niektóre z nich wymagają jednak dokładniejszego wytłumaczenia:
speed (prędkość maksymalna) - niby wszystko jasne, lecz OTTD wprowadza szereg zaokrągleń w trakcie dokonywanych przeliczeń, przez co prędkość widoczna w grze czasem odbiega dość mocno od tej zadanej w GRF-ie. Dlatego należy ją doświadczalnie zwiększyć o 1-3 km/h, aby uzyskać wynik jak najbardziej zbliżony do żądanego.
weight (ciężar) - w przypadku pojazdu przegubowego jest to masa całego pojazdu. Dla Pt31 podana jest więc suma ciężaru lokomotywy (106 ton) oraz jej węglarki (67 ton).
tractive_effort_coefficient (współczynnik maksymalnej siły pociągowej) - współczynnik określający jaka część ciężaru pojazdu przekłada się na jego siłę pociągową. W przypadku pojazdów szynowych przyjmuje się 0.3 (30%). Dla parowozu współczynnik ten musi być jeszcze skorygowany ze względu na fakt, że nie wszystkie osie parowozu są napędzane. W przypadku Pt31 nacisk na jedną oś napędową wynosi 18,3 tony. Po przemnożeniu przez 4 osie mamy "zaledwie" ok. 74 ton masy czynnej w porównaniu ze 173 tonami masy całkowitej.
Dodanie obsługi przegubowości
Najistotniejszym etapem tworzenia pojazdu przegubowego jest napisanie odpowiednich funkcji (switch-y), odpowiedzialnych za realizację efektów przegubowości:
Kod:
/* Pt31 switches */
switch(FEAT_TRAINS, SELF, switch_pt31_articulated, extra_callback_info1) {
1: return item_pt31; // Add tender
return 0xFF;
}
switch(FEAT_TRAINS, SELF, switch_pt31_graphics, position_in_vehid_chain % 2) {
0: return spriteset_pt31;
return spriteset_pt31_tender;
}
switch(FEAT_TRAINS, SELF, switch_pt31_visual_effect, position_in_vehid_chain % 2) {
0: return visual_effect_and_powered(VISUAL_EFFECT_STEAM, -4, DISABLE_WAGON_POWER);
return visual_effect_and_powered(VISUAL_EFFECT_DISABLE, 0, DISABLE_WAGON_POWER);
}... oraz podpięcie ich pod odpowiednie callback-i w sekcji graphics pojazdu:
Kod:
graphics {
purchase: spriteset_pt31_purchase;
default: switch_pt31_graphics;
articulated_part: switch_pt31_articulated;
visual_effect_and_powered: switch_pt31_visual_effect;
}Callback-iem decydującym o istnieniu przegubowości jest callback articuladed_part. Podpiety pod niego swith switch_pt31_articulated jest wywoływany w trakcie tworzenia pojazdu wielokrotnie, w celu określenia identyfikatorów dodatkowych członów pojazdu. Za każdym wywołaniem swoitch-a w jego parametrze extra_callback_info1 znajduje się numer kolejnego członu pojazdu. Zwracaną przez switch wartością powinien być identyfikator tego kolejnego członu lub wartość 0xFF, oznaczająca koniec pojazdu.
W naszym przypadku zarówno lokomotywa, jak i jej węglarka, powinny mieć dokładnie ten sam identyfikator (parowóz jest pojazdem nierozdzielnym), dlatego na pytanie o drugi człon pojazdu (extra_callback_info1 = 1) zwracany jest również identyfikator item_pt31.
Drugi ze zdefiniowanych switch-y, switch_pt31_graphics odpowiada za właściwą wizualizację parowozu jako pojazdu przegubowego. Konieczność stworzenia tego switcha wynika z faktu, że wszystkie człony parowozu mają ten sam identyfikator. Musimy więc poinformowac grę, kiedy w ramach tego samego identyfikatora item_pt31 ma wyświetlić lokomotywę, a kiedy węglarkę.
Decyzja ta jest podejmowana na podstawie parametru position_in_vehid_chain, który określa ni mniej, ni więcej, tylko kolejną pozycję danego członu w łańcuchu pojazdów o tym samym identyfikatorze. W pokazanym przypadku wartość ta jest jeszcze poddana operacji modulo 2, aby właściwe sprite-y były wyświetlane także dla kolejnych lokomotyw w składzie, jadących w tzw. "trakcji wielokrotnej".
Trzeci switch, switch_pt31_visual_effect pełni bardzo podobną rolę, co poprzedni switch, lecz dotyczy "efektów specjalnych" wyświetlanych przez grę. Zadaniem tego switcha jest spowodowanie, że dym z komina będzie generowany jedynie przez lokomotywę. Węglarka będzie miała nieaktywne wszelkie efekty.
Kompletny kod NewGRF
Poniżej zamieszczam pełną treść plików, niezbędnych do skompilowania dodatku:
custom_tags.txt
Kod:
VERSION :0.1.0
TITLE :Pt31lang/english.lng
Kod:
##grflangid 0x01
# This is the English language file
# GRF name and description
STR_GRF_NAME :{TITLE} {VERSION}
STR_GRF_DESCRIPTION :{ORANGE}{TITLE} - polish steam locomotive.{BLACK}{}{COPYRIGHT}2011 {WHITE}Tadeusz Domagalski{BLACK}{}License: GPL v2
STR_PT31_NAME :Pt31 (Steam)lang/polish.lng
Kod:
##grflangid 0x30
# Polska wersja językowa
# Nazwa GRF oraz opis
STR_GRF_NAME :{TITLE} {VERSION}
STR_GRF_DESCRIPTION :{ORANGE}Polski parowóz {TITLE}.{BLACK}{}{COPYRIGHT}2011 {WHITE}Tadeusz Domagalski{BLACK}{}License: GPL v2
STR_PT31_NAME :Pt31 (Parowóz)pt31.nml
Kod:
grf {
grfid: "TD\01\02";
name: string(STR_GRF_NAME);
desc: string(STR_GRF_DESCRIPTION);
version: 0;
min_compatible_version: 0;
}
/* graphics definition */
template template_sprite_train10(x, y) {
// [left_x, upper_y, width, height, offset_x, offset_y]
[x, y, 10, 32, -5, -14]
[x+ 18, y, 30, 30, -20, -18]
[x+ 54, y, 44, 20, -26, -14]
[x+104, y, 30, 30, -12, -20]
[x+140, y, 10, 32, -5, -18]
[x+158, y, 30, 30, -16, -20]
[x+194, y, 44, 20, -18, -14]
[x+244, y, 30, 30, -8, -18]
}
template template_sprite_train(x, y) {
// [left_x, upper_y, width, height, offset_x, offset_y]
[x, y, 10, 28, -5, -14]
[x+ 16, y, 26, 28, -16, -18]
[x+ 46, y, 36, 20, -18, -14]
[x+ 86, y, 26, 28, -8, -18]
[x+120, y, 10, 28, -5, -14]
[x+136, y, 26, 28, -16, -18]
[x+166, y, 36, 20, -18, -14]
[x+206, y, 26, 28, -8, -18]
}
template template_sprite_purchase(x, y) {
// [left_x, upper_y, width, height, offset_x, offset_y]
[x, y, 50, 12, -25, -6]
}
/* Pt31 sprites */
spriteset(spriteset_pt31_purchase, "gfx/pt31.png") {
template_sprite_purchase(4, 100)
}
spriteset(spriteset_pt31, "gfx/pt31.png") {
template_sprite_train10(4, 20)
}
spriteset(spriteset_pt31_tender, "gfx/pt31.png") {
template_sprite_train(4, 60)
}
/* Pt31 switches */
switch(FEAT_TRAINS, SELF, switch_pt31_articulated, extra_callback_info1) {
1: return item_pt31; // Add tender
return 0xFF;
}
switch(FEAT_TRAINS, SELF, switch_pt31_graphics, position_in_vehid_chain % 2) {
0: return spriteset_pt31;
return spriteset_pt31_tender;
}
switch(FEAT_TRAINS, SELF, switch_pt31_visual_effect, position_in_vehid_chain % 2) {
0: return visual_effect_and_powered(VISUAL_EFFECT_STEAM, -4, DISABLE_WAGON_POWER);
return visual_effect_and_powered(VISUAL_EFFECT_DISABLE, 0, DISABLE_WAGON_POWER);
}
/* Define the actual train */
item(FEAT_TRAINS, item_pt31) {
property {
/* common properties */
name: string(STR_PT31_NAME);
climates_available: bitmask(CLIMATE_TEMPERATE, CLIMATE_ARCTIC);
introduction_date: date(1931, 1, 1);
model_life: VEHICLE_NEVER_EXPIRES;
vehicle_life: 30;
reliability_decay: 20;
refittable_cargo_classes: bitmask(CC_PASSENGERS);
non_refittable_cargo_classes: bitmask();
refittable_cargo_types: bitmask();
loading_speed: 5;
cost_factor: 18; // 7% (18=7%, 20=8%)
running_cost_factor: 122; // 48% (122=48%)
/* train properties */
sprite_id: SPRITE_ID_NEW_TRAIN;
speed: 111 km/h;
misc_flags: bitmask();
refit_cost: 0;
track_type: RAIL;
ai_special_flag: AI_FLAG_PASSENGER;
power: 1471 kW;
running_cost_base: RUNNING_COST_STEAM;
dual_headed: 0;
cargo_capacity: 0;
weight: 173 ton; // 106+67 ton
ai_engine_rank: 0; // not intended to be used by the ai
engine_class: ENGINE_CLASS_STEAM;
extra_power_per_wagon: 0 kW;
tractive_effort_coefficient: 0.3*74/173;
air_drag_coefficient: 0.07;
shorten_vehicle: SHORTEN_TO_8_8;
extra_weight_per_wagon: 0;
visual_effect_and_powered: visual_effect_and_powered(VISUAL_EFFECT_DEFAULT, 0, DISABLE_WAGON_POWER);
extra_weight_per_wagon: 0 ton;
bitmask_vehicle_info: 0;
}
graphics {
purchase: spriteset_pt31_purchase;
default: switch_pt31_graphics;
articulated_part: switch_pt31_articulated;
visual_effect_and_powered: switch_pt31_visual_effect;
}
}Na koniec przedstawiam zrzut ekranu, przedstawiający różne przykłady szynowych pojazdów przegubowych pod OTTD
:
![OpenTTD #Polska - Polskie forum gry OpenTTD [ARCHIWUM] OpenTTD #Polska - Polskie forum gry OpenTTD [ARCHIWUM]](https://forum.openttd.pl/images/logo.png)
