INNE Tworzenie NewGRF w NML #2 - parowóz Pt31 i inne pojazdy przegubowe.
#2
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:
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        :Pt31

lang/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 Wink :

[Obrazek: 550Pt31_Bipa.png]


Wiadomości w tym wątku

Skocz do:

[-]
Zamknięcie forum OpenTTD Polska
Forum OpenTTD Polska zostało wyłączone. Obecnie znajduje się tu archiwum dyskusji o dodatkach tworzonych przez naszą społeczność.
Po aktualne treści i dyskusje zapraszamy na nasz discord! :)

[-]
Discord