INNE Tworzenie NewGRF w NML #1 - drezyna WM-15A.
#4
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...Sad
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]

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]

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;
...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 ):
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;
    }
}


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