Skocz do zawartości

[Tutorial] Tworzenie stalkerskich obozów oraz dodawanie NPC do gry.


Rekomendowane odpowiedzi

Tytułem wstępu...

Poprzedni tutorial traktował o uproszczonej metodzie tworzenia obozowisk [general_lager] oraz [general_lair], w której korzystając z funkcji respawnu jednostek - skracaliśmy czas potrzebny na przygotowanie smart_terrain'a. Wadą tej metody był brak możliwości stworzenia (dla tego typu obozowiska) charakterystycznych postaci (z uwagi na losowy spawn NPC'ów), jak np. handlarze, zleceniodawcy, mechanicy etc., oraz długi czas respawnu. Ten poradnik przedstawia sposób umożliwiający tworzenie obozów znacznie bardziej rozbudowanych, w których wprowadzamy postacie zgodnie z naszym zamiarem, konfigurując poprzez odpowiednie pliki - ich cechy jak: wygląd, uzbrojenie, zachowanie (np. wartownik, zleceniodawca, snajper, handlarz etc.) oraz poprzez dodanie odpowiednich kwestii dialogowych - wprowadzając możliwość wykonywania zadań dla nowo utworzonych NPC'ów. Jest to metoda szczegółowa, ponieważ prócz budowy samego smart terrain'a narzuca wymóg konfiguracji wielu plików, bez których obozowisko nie będzie funkcjonować. Wpierw warto zapoznać się z początkową częścią tego poradnika (Link), dotyczącą opisu działania narzędzia "Smartterrain and Waypoint Tools by dez0wave" za pomocą którego będziemy wyznaczać współrzędne terenowe obiektów spawnowanych (koordynaty X,Y,Z, game_vertex_id, level_vertex_id), ścieżki patrolowe i kierunki widzenia NPC'ów. Omawiane powyżej narzędzie jest dostępne pod linkiem:

http://sdk.stalker-game.com/en/images/d/d7/Smartterrain_and_Waypoint_Tools_by_dez0wave.zip

Gdyby doszło do sytuacji, iż podany link wygaśnie - dodaję załącznik z w/w narzędziem Smartterrain_and_Waypoint_Tools_by_dez0wave.zip

Uwagi dot. tekstu ujętego w code

Jeśli dojdzie do sytuacji, iż kod potrzebny do skopiowania zostanie rozwarstwiony - przykład, np. podczas przenoszenia, edycji posta lub instalacji dodatków do edycji tekstu, wówczas należy kopiować fragmenty bez podanych w przykładzie odstępów w wierszach lub pobrać kod zawarty w załączniku: część kodu dla skopiowania.7z

Są to większe fragmenty, których (w przypadku rozwarstwienia) przerobienie byłoby czasochłonne, jednakże nie jest to cały poradnik!

 

I. Etap przygotowawczy.

Moim zamiarem jest stworzenie obozowiska składającego się z 10 stalkerów, zlokalizowanych na starej stacji benzynowej na Zatonie. Zasada ogólna: na 1 jednostkę wprowadzaną do gry (NPC/mutant) należy zebrać min. 3 punkty terenowe. Zasada nie tyczy się jednostek patrolujących, dla których ilość zbieranych punktów jest zależna od długości oraz złożoności trasy. Warto uzmysłowić sobie ten fakt, ponieważ musimy zebrać odpowiednią ilość współrzędnych do określenia złożoności zadań, które zostaną przydzielone NPC'om w ramach przypisanego im smart terrain'a.

Pomimo iż poradnik jest pod Cień Czarnobyla 1.0004, dodatkowe mapy wykorzystane w jego przygotowaniu pochodzą z modyfikacji wprowadzającej dodatkowe poziomy do gry: Stalker Map Pack volume 1 (SMP1) + with Addons (by Kostya), całość dostępna pod linkiem:

http://www.amk-team.ru/forum/index.php?showtopic=5533&p=197946

Punkty zebrane poniżej (spoilery) - wytyczone zostały na lokacji Zaton, jeśli chcemy stworzyć obozowisko na innej mapie - musimy obrać dla niej właściwe współrzędne, wspominam o tym - być może oczywistym fakcie - z uwagi na różny poziom zaawansowania adeptów moddingu stalkera.

  • By zespawnować smart terrain, space restrictor oraz stalkerów, będę potrzebował następujących punktów terenowych (dla pliku alife_*.ltx): * - nazwa mapy
    Punkty zebrane w pobliżu bazy.

    ! Unknown command:  patrolName=smart_terrain_zaton|anim=spawn|sig=p2|pos=-164.29083251953,20.028587341309,-170.58624267578|game=3672|level=612205* Log file has been saved successfully!! Unknown command:  patrolName=Space_restrictor|anim=s1|sig=p1|pos=-164.02833557129,20.026166915894,-170.90342712402|game=3672|level=613648* Log file has been saved successfully!Stalkerzy - spawn w odległości 50 metrów od obozowiska:! Unknown command: + patrolName=stalker_1|anim=spawn|pos=-178.02299499512,20.006784439087,-199.22261047363|game=3671|level=585219* Log file has been saved successfully!! Unknown command: + patrolName=stalker_2|anim=spawn|pos=-173.8215637207,19.889699935913,-199.88563537598|game=3671|level=593362* Log file has been saved successfully!! Unknown command: + patrolName=stalker_3|anim=spawn|pos=-168.51168823242,19.857637405396,-199.91232299805|game=3671|level=603622* Log file has been saved successfully!! Unknown command: + patrolName=stalker_4|anim=spawn|pos=-164.84016418457,19.853427886963,-199.74124145508|game=3671|level=612164* Log file has been saved successfully!! Unknown command: + patrolName=stalker_5|anim=spawn|pos=-159.72367858887,19.936441421509,-205.45335388184|game=3673|level=622235* Log file has been saved successfully!! Unknown command: + patrolName=stalker_6|anim=spawn|pos=-173.2433013916,19.859149932861,-190.16191101074|game=3672|level=594831* Log file has been saved successfully!! Unknown command: +  patrolName=stalker_7|anim=spawn|pos=-166.11315917969,19.595960617065,-189.74349975586|game=3672|level=609291* Log file has been saved successfully!! Unknown command: +  patrolName=stalker_8|anim=spawn|pos=-160.61776733398,19.283771514893,-190.16513061523|game=3673|level=620821* Log file has been saved successfully!! Unknown command: + patrolName=stalker_9|anim=spawn|pos=-162.41532897949,19.694192886353,-181.04301452637|game=3672|level=616484* Log file has been saved successfully!! Unknown command:  patrolName=stalker_10|anim=spawn|pos=-167.70727539063,19.810117721558,-179.84205627441|game=3672|level=605071* Log file has been saved successfully!! Unknown command: + patrolName=ogien|anim=spawn|pos=-162.70420837402,19.901027679443,-154.37886047363|game=3672|level=616516* Log file has been saved successfully!

    Powyżej - wyciąg z loga zawierający koordynaty + opis dot. spawnowanych obiektów: Poniższy screen ilustruje zasadę zbierania potrzebnych współrzędnych dla jednostek niepatrolujących
    post-3466-0-76533600-1377095594_thumb.pn
  • Kolejne punkty koordynatów (zebrane w spoiler) dotyczą konfiguracji ścieżek patrolowych, miejsc zajmowanych w obiekcie przez stalkerów, kierunków patrzenia NPC'ów (dla pliku way_*.ltx
    dla strażnika potrzebujemy min. 3 pkt: zajmowanej pozycji oraz kierunek patrzenia (3 współrzędna to spawn - patrz wyciąg z loga powyżej)
    dla snajpera potrzebujemy min. 3 pkt: spawn, zajmowana pozycja oraz kierunek patrzenia.
    leader obozu będzie również potrzebował min. 3 pkt: spawn, pozycja zajmowana, kierunek patrzenia.

post-3466-0-12695800-1377095961_thumb.pn

 

Powyżej - szkic poglądowy obozowiska z naniesioną trasą patrolową. Trasa NPC omówiona została w pkt. 7 poradnika.

Generalnie - stalkerzy, którzy stoją w jednej pozycji - nie wymagają wielu punktów do zdefiniowania ich zachowania, oczywiście ilość wprowadzonych punktów zależeć będzie od schematu wg. którego będzie się przemieszczał NPC. Możemy wprowadzić np. zmieniającego pozycję snajpera czy wędrującego leadera - decyzja należy do nas, warto jednak zacząć od prostych tras NPC'a, by wyrobić sobie sprawność tworzenia obozowisk, które wymagają wiele cierpliwości do moddera.

Poniżej wyciąg z loga dot. współrzędnych zbieranych dla pliku way_*.ltx (w moim przykładzie plik: way_zaton.ltx uzyskany po dekompilacji all.spawn)

! Unknown command:  patrolName=guard_1|anim=path_1|pos=-155.5466003418,20.028352737427,-166.75846862793|game=3672|level=631044* Log file has been saved successfully!! Unknown command:  patrolName=guard_1|anim=look_1|pos=-153.0920715332,19.814691543579,-168.40322875977|game=3672|level=635599* Log file has been saved successfully!! Unknown command:  patrolName=guard_1|anim=look_2|pos=-153.6296081543,19.748586654663,-164.44575500488|game=3672|level=635605* Log file has been saved successfully!! Unknown command:  patrolName=guard_2|anim=path_2|pos=-166.96611022949,20.028186798096,-161.50028991699|game=3672|level=606498* Log file has been saved successfully!! Unknown command:  patrolName=guard_2|anim=look_2-1|pos=-165.00396728516,19.832225799561,-158.97044372559|game=3672|level=610766* Log file has been saved successfully!! Unknown command:  patrolName=guard_3|anim=path_3|pos=-167.32208251953,20.02885055542,-161.49401855469|game=3672|level=606498* Log file has been saved successfully!! Unknown command:  patrolName=guard_3|anim=look_3|pos=-167.43406677246,19.83323097229,-157.86051940918|game=3672|level=606502* Log file has been saved successfully!! Unknown command:  patrolName=guard_4|anim=path_4|pos=-165.72045898438,20.02819442749,-166.74816894531|game=3672|level=609320* Log file has been saved successfully!! Unknown command:  patrolName=guard_4|anim=look_4|pos=-163.19924926758,20.029188156128,-166.2618560791|game=3672|level=615065* Log file has been saved successfully!! Unknown command:  patrolName=hidden_1|anim=path_1|pos=-157.36337280273,20.028509140015,-172.5984954834|game=3672|level=626645* Log file has been saved successfully!! Unknown command:  patrolName=hidden_1|anim=look_1|pos=-159.47149658203,19.776128768921,-178.98678588867|game=3672|level=622267* Log file has been saved successfully!! Unknown command:  patrolName=hidden_1|anim=look_1-2|pos=-152.04862976074,20.225852966309,-175.70111083984|game=3672|level=638596* Log file has been saved successfully! Unknown command:  patrolName=hidden_2|anim=path_2|pos=-168.58984375,20.029529571533,-169.03833007813|game=3672|level=603661* Log file has been saved successfully!! Unknown command:  patrolName=hidden_2|anim=look_2-1|pos=-172.7536315918,19.877557754517,-177.65606689453|game=3672|level=594849* Log file has been saved successfully!! Unknown command:  patrolName=hidden_2|anim=look_2-2|pos=-176.77577209473,19.8899269104,-172.32081604004|game=3672|level=586539* Log file has been saved successfully!! Unknown command:  patrolName=leader_1|anim=path_1|pos=-171.01541137695,20.028509140015,-166.41958618164|game=3672|level=599270* Log file has been saved successfully!! Unknown command:  patrolName=leader_1|anim=look_1|pos=-169.37171936035,20.028509140015,-165.0013885498|game=3672|level=602222* Log file has been saved successfully!! Unknown command:  patrolName=sitting_stalker|anim=path_1|pos=-163.43371582031,20.028532028198,-163.29096984863|game=3672|level=615070* Log file has been saved successfully!! Unknown command:  patrolName=sitting_stalker|anim=look_1|pos=-164.66107177734,20.028505325317,-163.32861328125|game=3672|level=612214* Log file has been saved successfully!--- trasa_patrolowa ---! Unknown command:  patrolName=patrol_1|anim=walk_0|pos=-177.95030212402,19.892816543579,-170.10719299316|game=3672|level=585261* Log file has been saved successfully!! Unknown command:  patrolName=patrol_1|anim=walk_1|pos=-178.44303894043,20.010766983032,-188.76034545898|game=3672|level=583941* Log file has been saved successfully!! Unknown command:  patrolName=patrol_1|anim=walk_2|pos=-178.22425842285,20.006406784058,-191.03433227539|game=3672|level=583938* Log file has been saved successfully!! Unknown command:  patrolName=patrol_1|anim=walk_3|pos=-155.91751098633,19.15784072876,-189.83374023438|game=3673|level=629541* Log file has been saved successfully!! Unknown command:  patrolName=patrol_1|anim=walk_4|pos=-155.81336975098,19.577337265015,-192.12979125977|game=3673|level=629538* Log file has been saved successfully!! Unknown command:  patrolName=patrol_1|anim=walk_5|pos=-153.88307189941,19.837575912476,-170.7787322998|game=3672|level=634065* Log file has been saved successfully!! Unknown command:  patrolName=patrol_1|anim=walk_6|pos=-153.67362976074,19.787631988525,-168.28823852539|game=3672|level=634069* Log file has been saved successfully!! Unknown command:  patrolName=patrol_1|anim=walk_7|pos=-153.6607208252,19.696378707886,-159.70063781738|game=3672|level=634081* Log file has been saved successfully!! Unknown command:  patrolName=patrol_1|anim=walk_8|pos=-153.5884552002,19.616180419922,-158.62452697754|game=3672|level=635611* Log file has been saved successfully!! Unknown command:  patrolName=patrol_1|anim=walk_9|pos=-175.44000244141,19.932542800903,-159.28170776367|game=3672|level=589203* Log file has been saved successfully!! Unknown command:  patrolName=patrol_1|anim=walk_10|pos=-175.66333007813,19.933841705322,-157.82580566406|game=3672|level=589206* Log file has been saved successfully!! Unknown command:  patrolName=patrol_1|anim=walk_11|pos=-175.61622619629,19.892559051514,-166.17030334473|game=3672|level=589194* Log file has been saved successfully!! Unknown command: --- punkt przy ognisku oraz położenie modelu ogniska ---! Unknown command:patrolName=kamp_point|anim=spawn1|pos=-162.73413085938,19.791074752808,-154.43911743164|game=3672|level=616516* Log file has been saved successfully!! Unknown command:  patrolName=ognisko_model|pos=-162.70478820801,19.790044784546,-154.41091918945|game=3672|level=616516* Log file has been saved successfully!

 

 

II. Etap wykonawczy.

Poszczególne punkty poradnika oraz wykaz potrzebnych plików ilustruje poniższy załącznik:

 

post-3466-0-74956200-1377097256_thumb.pn

  • Dekompilujemy plik all.spawn zgodnie z tym poradnikiem (Link), uzyskując interesujące nas pliki alife_*.ltx oraz way_*.ltx 
    * - nazwa mapy.
  • W zależności od miejsca dodawania smart terrain'a, wybieramy odpowiedni plik - w moim przykładzie tworzę obozowisko na Zatonie, dlatego korzystam z plików:
    alife_zaton.ltx
    way_zaton.ltx
  • W pierwszej kolejności tworzę smart terrain dodając do pliku alife_zaton.ltx z zachowaniem odpowiedneiej numeracji (brak powtórzeń numeru obiektu) wpis następujący:

    [11627]; cse_abstract propertiessection_name = smart_terrainname = zat_gas_stationposition = -164.29083251953,20.028587341309,-170.58624267578direction = 0,0,0; cse_alife_object propertiesgame_vertex_id = 3672distance = 14.6999998092651level_vertex_id = 612205object_flags = 0xffffff3ecustom_data = <<END[smart_terrain]type = zat_gas_stationcapacity = 10squad    = 1groups = 9END; cse_shape propertiesshapes = shape0shape0:type = sphereshape0:offset = 0,0,0shape0:radius = 5.86660003662109; cse_alife_space_restrictor propertiesrestrictor_type = 3; se_smart_terrain properties



    Omówienie parametrów sekcji:
    [11627] - numer obiektu (warunek konieczny dotyczący wszystkich plików .ltx uzyskanych po dekompilacji: numery nie mogą się powtarzać!)
    section_name = smart_terrain - jest to wpis definiujący obiekt stanowiący obszar, w którym określone typy jednostek (NPC/mutanty) realizują zdefiniowane skryptem (gulag_*.script) zadania, innymi słowy - stalkerskie obozowisko. Jest to parametr niepodlegający edycji dla tego typu obiektu!
    name = zat_gas_station - jest to nazwa (dowolna) nowo utworzonego smart terrain'a. Ważna uwaga, występujący w name - wpis musi być powtórzony również w parametrze type, tzn.

    name = type
    Tworząc nowy smart terrain w odróżnieniu od general_lager (dla NPC) czy general_lair (dla mutantów), pamiętajmy by wpisy stojące przy omówionych parametrach były jednakowe!
    position - są to koordynaty spawnu naszego obiektu (X,Y,Z).
    direction - obrót obiektu, który z uwagi na sferyczny kształt smart terrain'a możemy ustawić na 0,0,0. Gdyby kształt obiektu był określony jako box (graniastosłup prawidłowy czworokątny) wówczas parametr direction miałby znaczenie. Ponieważ kształt smart terrain'a widać dopiero na etapie projektowania z użyciem SDK, możemy ułatwić sobie pracę poprzez ustanowienie kształtu sferycznego.
    game_vertex_id, level_vertex_id - punkty wierzchołkowe uzyskane dzięki Smartterrain and Waypoint Tools by dez0wave (zapis koordynatów w logu).
    distance - parametr którego zmiana podczas testowania nie wpłynęła znacząco na rozgrywkę. Zawsze parametr odległości zawieram w przedziale 10 do 20 jednostek. Jeśli tworząc smart terrain masz wątpliwości jakie wartości przyporządkować do distance, sprawdź poprzez analogię obozowiska pierwotnie zaimplementowane przez GSC w niemodowanym SHOC jako wzorce z pomocą których dobierzesz wartości adekwatne do tworzonego smart terrain'a.
    type - zgodnie z tym co wcześniej pisałem, typ smart terrain'a jest równy wpisowi w name i tej zasady należy się bezwzględnie trzymać tworząc obozowisko stalkerów o unikalnych cechach - bez losowego udziału spawn'a NPC/mutantów.
    capacity - ilość obsługiwanych przez smart terrain NPC lub mutantów.
    groups, squad - są parametrami opcjonalnymi, przy ich doborze kieruję się wzorcami istniejących już smart terrain'ów. np. esc_lager (smart terrain wioski nowicjuszy z Kordonu - patrz plik alife_l01_escape.ltx), ponieważ wartości powyższe nie wpływają na pracę jednostek obsługiwanych przez smart terrain. Jeśli parametrów tych nie zdefiniujemy - gra ustawi wartości defaultowe.
    shape0:type = sphere - określenie kształtu smart terrain'a jako sfery. (kształt nie jest widoczny bez SDK) 
    shape0:radius - promień sfery smart terrain'a. Wartość nie ma wpływu na stan pracy stalkerów. Parametr nie decyduje o odległości na jaką stalker może oddalić się od obozowiska! jadnakże nie można jej pominąć. Wartość min. = 1.
    restrictor_type = 3 - bardzo ważny wpis. Ilekroć tworzę obozowisko unikalnych NPC/mutantów, tj. obiektów w których parametry name = type, wówczas wartość restrictor_type jest zawsze równa 3. Jeśli ustawię wartość 0, wówczas przy rozpoczynaniu nowej gry spotkamy się z CTD o treści:
    FATAL ERROR[error]Description   : any vertex in patrol path*...is inaccessible for object **...
    * - ścieżka patrolowa zdefiniowana w way_*.ltx
    ** - obiekt np. NPC określony w alife_*.ltx, przemieszczający się zgodnie ze ścieżką patrolową.
    Należy mieć na uwadze w/w informacje, ponieważ są bardzo istotne.
    Wskazówka ogólna: aby proces kompilacji przebiegał prawidłowo, dodając kolejne obiekty do plików alife_*.ltx, way_*.ltx - należy zachować pomiędzy dodawanymi sekcjami odstępy 2 wierszy.
  • Do pliku alife_*.ltx (alife_zaton.ltx) dodaję wpis odnoszący się do space_restrictor, który jest immanentnym elementem pracy smart terrain'a (jest wykorzystywany przez pliki gulag_*.script w moim przykładzie). Space restrictor w zależności od dodatkowych wpisów (np. active = sr_no_weapon) - pełni różną funkcję, np. powoduje, iż gracz w jego strefie (np. bunkier Sidorowicza, bar etc.) chowa broń. W tym przypadku - obszar ten wykorzystują NPC w pliku gulag_*.script jako dodatkowy punkt odniesienia, gdy oddalą się od obozowiska np. wskutek ataku.
    * - nazwa mapy.
    analizując wpisy space_restrictor można zauważyć, iż game_vertex_id = 0. (na podst. analizy 77 wpisów z pliku alife_l01_escape.ltx). Dodawany wpis ma postać następującą:

    [11628]; cse_abstract propertiessection_name = space_restrictorname = gas_station_teamposition = -164.02833557129,20.026166915894,-170.90342712402direction = 0,0,0; cse_alife_object propertiesgame_vertex_id = 0distance = 0level_vertex_id = 613648object_flags = 0xffffff3e; cse_shape propertiesshapes = shape0shape0:type = sphereshape0:offset = 0,0,0shape0:radius = 10; cse_alife_space_restrictor propertiesrestrictor_type = 3



    Opis parametrów sekcji jest taki sam jak w pkt.3 dot. smart terrain'a, toteż do niego odsyłam.
    Zwracamy uwagę, aby:

    restrictor_type = 3
  • Następny element pracy to zarejestrowanie nowego smart terrain'a. Stosowne wpisy (3 sekcje) należy umieścić w pliku gulag_*.script [gamedatascripts]. Możemy stworzyć nowy plik, jednak by skrócić proces tworzenia smart terrain'a możemy też wykorzystać istniejące pliki skryptu. W przykładzie - wpis umieszczę w pliku gulag_escape.script
    Wskazówki:
    Długość wpisu uzależniona jest od ilości jednostek przypisanych do smart terrain'a, w moim przykładzie 10 osobowa grupa. W jednym pliku dodaję 3 sekcje, zgrupowane w różnych jego częściach. Przykładowo: wpis dot. "esc_lager" (Shoc 1.0004) występuje w pliku gulag_escape.script w linijkach 293, 2048 oraz 2308. Każda sekcja określa różną funkcję - przykład podaję by można było na jego podstawie określić rozlokowanie wpisów w pliku.

     

    	 -- Zaton Gas Station, sekcja 1            if type == "zat_gas_station" then        -- Nowe_obozowisko        t = { section = "logic@zat_gas_station_guard1",            idle = 0,            prior = 10, state = {0, 1},            in_rest = "", out_rest = "gas_station_team"                }        table.insert(sj, t)                t = { section = "logic@zat_gas_station_guard2",            idle = 0,            prior = 11, state = {0, 1},            in_rest = "", out_rest = "gas_station_team",            predicate = function(obj_info)           		         return obj_info.story_id == 5489           			 end                    }                    table.insert(sj, t)        t = { section = "logic@zat_gas_station_guard3",            idle = 0,            prior = 10, state = {0, 1},            in_rest = "", out_rest = "gas_station_team"                }        table.insert(sj, t)        t = { section = "logic@zat_gas_station_guard4",            idle = 0,            prior = 10, state = {0, 1},            in_rest = "", out_rest = "gas_station_team"                }        table.insert(sj, t)        t = { section = "logic@zat_gas_station_guard5",            idle = 0,            prior = 10, state = {0, 1},            in_rest = "", out_rest = "gas_station_team"                }        table.insert(sj, t)        t = { section = "logic@zat_gas_station_guard6",            idle = 0,            prior = 10, state = {0},            in_rest = "", out_rest = "gas_station_team"                }        table.insert(sj, t)        t = { section = "logic@zat_gas_station_patrol1",            idle = 0,            prior = 10, state = {0, 1},            in_rest = "", out_rest = "gas_station_team"                }                table.insert(sj, t)        t = { section = "logic@zat_gas_station_kamp1",            idle = 0,            prior = 9, state = {0, 1},            in_rest = "", out_rest = "gas_station_team"                }        table.insert(sj, t)        t = { section = "logic@zat_gas_station_kamp1",            idle = 0,            prior = 9, state = {1},            in_rest = "", out_rest = "gas_station_team"                }                table.insert(sj, t)            t = { section = "logic@zat_gas_station_tvmaniak",            idle = 0,            prior = 10, state = {0, 1},            in_rest = "", out_rest = "gas_station_team",            predicate = function(obj_info)           		         return obj_info.profile_name == "zat_tv_maniak"           			 end                    }                table.insert(sj, t)                t = { section = "logic@zat_gas_station_leader",            idle = 0,            prior = 12, state = {0, 1},            in_rest = "", out_rest = "gas_station_team",            predicate = function(obj_info)           		         return obj_info.story_id == 5481           			 end                    }                table.insert(sj, t)    end        -- Zaton Gas Station, sekcja 2    if type == "zat_gas_station" then        return function(gulag)            if db.actor ~= nil then                if ( level.get_time_hours() >= 5 and level.get_time_hours() <= 22 ) then                    return 0  -- tryb dzienny                else                    return 1  -- tryb nocny                end            else                return gulag.state            end        end    end                    -- Zaton Gas Station, sekcja 3    if gulag_type == "zat_gas_station" then        return npc_community == "stalker"    end    


    Omówienie parametrów sekcji 1:
    rozdzielenie parametrów.

    t = { section = "logic@zat_gas_station_guard1", idle = 0, prior = 10, state = {0, 1}, in_rest = "", out_rest = "gas_station_team"}
    Zapis w postaci 1-wierszowej znacznie lepiej zwraca uwagę na konieczność oddzielenia parametrów przecinkiem - być może uwaga jest truistyczna, jednak wystarczy brak przecinka w jednym tylko miejscu by skrypt nie funkcjonował prawidłowo, zaś duża ilość jednostek, które będą obsługiwane przez smart terrain, to duża ilość wpisów przy których łatwo można pominąć - tak wydawać by się mogło - mało istotną sprawę, dlatego zwracam uwagę na konieczność dokładnego sprawdzenia tworzonego skryptu obozowiska pod kątem odseparowania każdego z parametrów.

    logic@zat_gas_station_guard1
    jest to link do pliku gulag_*.ltx (w przykładzie gulag_escape.ltx) lokalizacja:[gamedataconfigmisc], w którym znajduje się wpis wiążący skrypt (gulag_*.script) z plikiem way_*.ltx. Ów wpis łączy skrypt z schematem działania NPC. Opis pliku gulag_*.ltx - w następnym punkcie.
    idle - to czas przeznaczony na przerwę pomiędzy wykonywaniem tego samego zadania przez skrypt. Gdy parametr ma wartość 0, wówczas obóz pracuje w sposób ciągły zapewniając stalkerom 24 godz. tryb pracy.
    prior - stopień ważności zadania, który im jest wyższy - tym zadanie (np. patrolowanie) jest ważniejsze. Zadania o wyższym priorytecie są podejmowane przez zespawnowanych stalkerów w pierwszej kolejności (z wyjątkiem parametru "predicate")
    state = {0, 1} oznacza, iż zadanie, które zdefiniujemy jednostce - jest wykonywane w cyklu dzień-noc.Jeśli ustawię state = {0}, wówczas zadanie bedzie dostępne tylko podczas dnia. Przy state = {1} - zadanie jest realizowane nocą.
    Jeśli wybiorę jedną z opcji tj, state 0 lub 1 wówczas muszę stworzyć jednostce róznież zadanie ekwiwalentne dla drugiego trybu. Innymi słowy - jeśli NPC będzie patrolował z parametrem state = {0}, wówczas po zapadnięciu zmroku - opuści obozowisko, ponieważ smart terrain nie znajdzie dla niego zadania, które będzie dostępne w nocy. Należy wówczas stworzyć dla takiej jednostki zadanie np. odpoczynek przy ognisku lub sen, z parametrem state = {1}, aby zapewnić jednostce możliwość realizowania zadania w cyklu dzień/noc.
    in_rest - opisuje ogranicznik (space_restrictor), który uniemożliwia wyjście stalkerom poza obszar obozowiska podczas walki. U mnie stalkerzy mają pełną swobodę opuszczania go w przypadku ataku, ponieważ in_rest = "" nie jest zdefiniowany.
    out_rest - wpis odnosi się do stworzonego obiektu z pkt. 4 tj. gas_station_team, które określa obszar pomocniczy dla stalkerów przebywających poza obozowiskiem. W moim przykładzie wzorowanym na obozowisku nowicjuszy z Kordonu, gdzie out_rest - został określony jako:

    out_rest = "gas_station_team"
    w/w wpis jest określony w pliku alife_zaton.ltx jako obiekt o numerze [11628], zespawnowany w pobliżu m-ca smart terrain'a.
    predicate - jest to wpis, który przydziela zadanie określonej postaci dzięki parametrowi profile_name, który znajduje się również w pliku alife_*.ltx (character_profile). Dzięki wpisowi, mamy pewność, że określony NPC np. leader - zajmie pozycję na której nam zależy. W niektórych przypadkach można wpis zdefiniować następująco (wartość 700 oznacza m-ce rankingowe stalkera):

    predicate = function(obj_info) return obj_info.rank >= 700 end

    Co oznacza, iż stalkerzy z reputacją równą lub większą niż 700 - będą realizować zdefiniowane zadanie (dla pozostałych będzie ono niedostępne). Innym sposobem na przydzieleniu postaci określonego zadania jest umieszczenie wpisu:

    predicate = function(obj_info) return obj_info.story_id == 5481

    Tylko postać o określonym numerze identyfikacyjnym, zgodnym z wpisami zawartymi w plikach: alife_*.ltx (parametr story_id - patrz punkt 8.1) oraz game_story_ids.ltx (omówienie w pkt. 8.4) - będzie realizować zadanie. 

    Omówienie parametrów sekcji 2: Funkcja która występuje w sekcji 2, została zdefiniowana do pracy w cyklu dobowym, określając czas [godz.] w którym następuje zmiana state = {0} na state = {1}

    Omówienie parametrów sekcji 3: wpis przyporządkowuje obozowisko określonej frakcji - w tym przypadku

    npc_community == "stalker"

    Wykaz frakcji i mutantów - plik game_relations.ltx [gamedataconfigcreatures].
    Sekcje 1,2,3 są obowiązkowe do wpisania!.

  • Kolejny etap to dodanie wpisów wiążących skrypt obozowiska ze schematem działania opartym o wyznaczone koordynaty. Musimy zgodnie z poprzednim plikiem gulag_*.script odszukać [gamedataconfigmisc] odpowiadający mu plik gulag_*.ltx.
    * - nazwa mapy.
    Ponieważ plik omawiany poprzednio to gulag_escape.script - odpowiadającym mu plikiem jest gulag_escape.ltx. Plik gulag_escape.ltx (zgodnie z obranym przykładem) uzupełniam o wpisy (pomiędzy kolejnymi sekcjami są 2-wierszowe odstępy): 

    ;-- Zaton Gas Station - start[logic@zat_gas_station_guard1]active = walker@zat_gas_station_guard1[walker@zat_gas_station_guard1]path_walk = patrol_walk1path_look = patrol_look1meet = meet@station[logic@zat_gas_station_guard2]active = walker@zat_gas_station_guard2[walker@zat_gas_station_guard2]path_walk = patrol_walk2path_look = patrol_look2meet = meet@station[logic@zat_gas_station_guard3]active = walker@zat_gas_station_guard3[walker@zat_gas_station_guard3]path_walk = patrol_walk3path_look = patrol_look3meet = meet@station[logic@zat_gas_station_guard4]active = walker@zat_gas_station_guard4[walker@zat_gas_station_guard4]path_walk = patrol_walk4path_look = patrol_look4meet = meet@station[logic@zat_gas_station_guard5]active = walker@zat_gas_station_guard5[walker@zat_gas_station_guard5]path_walk = patrol_walk5path_look = patrol_look5meet = meet@station[logic@zat_gas_station_guard6]active = walker@zat_gas_station_guard6[walker@zat_gas_station_guard6]path_walk = patrol_walk6path_look = patrol_look6meet = meet@station[logic@zat_gas_station_patrol1]active = walker@zat_gas_station_patrol1[walker@zat_gas_station_patrol1]path_walk = patrol_walk7[logic@zat_gas_station_kamp1]active = kamp@zat_gas_station[kamp@zat_gas_station]center_point  = camp3_center;path_walk = kamp_central_tasksoundgroup = zat_gas_station;meet = meet@lagerradius = 2.30[logic@zat_gas_station_tvmaniak]active = walker@zat_gas_station_tvmaniak[walker@zat_gas_station_tvmaniak]path_walk = movie_walkpath_look = movie_lookmeet = meet@station[logic@zat_gas_station_leader]active = walker@zat_gas_station_leader[walker@zat_gas_station_leader]path_walk = leader_walkpath_look = leader_lookmeet = meet@station[meet@station]use = trueuse_wpn = truemeet_talk_enabled = true;-- Zaton Gas Station - end



    Opis parametrów sekcji: Ogólnie rzecz ujmując - wpis: logic@Nazwa_Smart_Terraina + Identyfikator - musi występować w 2 plikach tj. gulag_*.ltx i gulag_*.script. W ten sposób wiąże się wpisami ścieżkę i kierunki patrzenia z określonym smart terrain'em. - porównaj wpisy z pkt. 5 i 6. Sprawa priorytetowa: ilość wpisów zawarta powyżej tj. [logic@...] jest zależna od ilości parametrów "section", zawartych w plikach gulag_*.script [gamedatascripts]. Warunek: Każdy z parametrów logic@ musi mieć odniesienie wpisowe w pliku gulag_*.script - patrz Zaton Gas Station, sekcja 1. Wyjątkiem jest (jeden) wpis [logic@zat_gas_station_kamp1], który jest wykorzystywany przez 2 postacie. (schemat pracy dotyczy punktu zajmowanego przy ognisku: pierwszy NPC zasiada przy ognisku przez całą dobę ponieważ state = {0, 1}, drugi NPC nocą zasiada do ogniska z uwagi na state = {1}, za dnia będąc wartownikiem stacji, gdyż state = {0} patrz plik omówiony w pkt.5 - guard6).

    [logic@zat_gas_station_guard1]
    Ujęty w nawias kwadratowy powyższy wpis, odnosi się do pliku skryptu gulag_*.script, w którym gra szuka w określonym smart terrain'ie (w moim przykładzie - zat_gas_station) sekcji logic@..***, którą zawierać powinny oba pliki gulag'u tj. wykorzystywany w przykładzie gulag_escape.ltx i gulag_escape.script (patrz pkt.5, sekcja 1 wpisu). W ten sposób tak samo nazwane schematy są łączone swoistym linkiem poprzez: logic@..****
    **** - nazwa smart terrain'a + wyróżniający schemat wpis np. kamp1
    active - parametr, który przyporządkowuje wartości [logic@..****], określony zbiór punktów poprzez path_walk i path_look. Jak możemy zauważyć na przykładzie:
    [logic@zat_gas_station_guard1]active = walker@zat_gas_station_guard1[walker@zat_gas_station_guard1]path_walk = patrol_walk1path_look = patrol_look1meet = meet@station
    Wpis [logic@zat_gas_station_guard1], wykorzystuje poprzez active zdefiniowany w nawiasie kwadratowym [walker@zat_gas_station_guard1] zbiór konkretnych koordynatów (ścieżka i kierunki patrzenia), wg. których NPC będzie pracował - patrolując, stojąc, siedząc, śpiąc czy atakując cel. Jak widzimy w prezentowanym przykładzie - zarówno logic@ jak i walker@ wykorzystują tę samą frazę: zat_gas_station, która jest nazwą utworzonego wcześniej w pliku alife_zaton.ltx - smart terrain'a (pkt. 3 poradnika - parametry "name" oraz "type"). Tworząc wpisy j/w musimy trzymać się zasady właściwego powiązania plików z utworzonym smart terrain'em, wykorzystując jego nazwę.
    path, look - są odnośnikami do koordynatów (X,Y,Z,game_vertex_id, level_vertex_id)zawartych w pliku way_*.ltx (w moim przykładzie: way_zaton.ltx).
    path_walk = patrol_walk1path_look = patrol_look1
    Punkty wyznaczają zajmowaną pozycję (path) oraz kierunek/ki patrzenia NPC (look).
    meet - wpis który definiuje zachowanie NPC, wg. którego będzie reagował na postać główną - ignorując ją, rozpoczynając rozmowę lub wykonując określoną animację zależną od rozbudowy tegoż wpisu. Zdefiniowany w moim przykładzie wpis to standardowy schemat postępowania. Musimy go dodać do pliku, ponieważ w oryginale ów wpis tj. meet@station - nie występuje (patrz ostatnia sekcja dodawana do pliku gulag_escape.ltx - spoiler).
    use_wpn = true ;-- możliwość używania broni przez NPCmeet_talk_enabled = true ;-- możliwość rozmowy z aktorem
    radius = 2.30 - parametr występujący przy definiowaniu pozycji NPC'a zajmującego określoną odległość od punktu centralnego (najczęściej zasiadający przy ogniskach NPC) - w tym przypadku odl. jest równa 2m 30 cm. Defaultowa wartość jest równa 2 metry. Tworząc większą ilość NPC korzystających z tego schematu - wartość promienia można zwiekszyć aby nie dochodziło do przepychanek stalkerów. Aby oszacować odległości warto włączyć w menu opcję - pokaż odległość od celu. Opcja przydaje się wówczas, gdy mamy zamiar stworzyć zasiadających przy ognisku stalkerów na obszarze ograniczonym innymi obiektami (mur, siatka, urwisko etc.) W przypadku błędnego oszacowania odległości, zbyt duża wartość promienia bedzie skutkowała błędem, ponieważ punkty przyporządkowane jednostce będą dla niej niedostępne z uwagi na przeszkody, których NPC nie bedzie w stanie pokonać.

     

    Chcąc ustalić za co odpowiadają poszczególne schematy obozowiska tj. [logic@zat_gas_station_*] (gdzie * oznacza identyfikator schematu), wystarczy przyjrzeć się jakie animacje przypisano do identyfikatora, przykładowo dla:

    [zat_gas_station_patrol_look1]

    mamy przyporządkowaną animację:

    p0:name = wp00|a=guard

    czyli postać będzie wartownikiem. Wyjątkiem jest schemat stalkerów zasiadających przy ognisku, gdzie schematem odpowiedzialnym jest w moim przypadku wpis:

    [zat_gas_station_camp3_center]

    istotnym wpisem rozpoznawanym przez grę jest camp3_center (numeracja może być inna). Przy frazie camp - gra wykorzystuje animacje stalkerów siedzących w określonej odległości od punktu centralnego. Animacje opisano w pkt. 7 poradnika.

     

  • Następna czynność to dodanie zebranych wcześniej koordynatów do pliku way_*.ltx (w przykładzie: way_zaton.ltx). Współrzędne - jak już wspominałem określają pozycje zajmowane przez NPC'ów, ich ścieżki patrolowe i kierunki patrzenia.

    [zat_gas_station_patrol_look1]points = p0,p1p0:name = wp00|a=guardp0:flags = 0x1p0:position = -153.0920715332,19.814691543579,-168.40322875977p0:game_vertex_id = 3672p0:level_vertex_id = 635599p1:name = wp01|a=guardp1:flags = 0x1p1:position = -153.6296081543,19.748586654663,-164.44575500488p1:game_vertex_id = 3672p1:level_vertex_id = 635605p1:links = p0(1)[zat_gas_station_patrol_walk1]points = p0p0:name = wp00p0:flags = 0x1p0:position = -155.5466003418,20.028352737427,-166.75846862793p0:game_vertex_id = 3672p0:level_vertex_id = 631044[zat_gas_station_patrol_look2]points = p0p0:name = wp00|a=binocularp0:flags = 0x1p0:position = -150.63876342773,19.411741256714,-153.86688232422p0:game_vertex_id = 3672p0:level_vertex_id = 641431[zat_gas_station_patrol_walk2]points = p0p0:name = wp00p0:flags = 0x1p0:position = -152.79585266113,19.469961166382,-153.48419189453p0:game_vertex_id = 3672p0:level_vertex_id = 637121[zat_gas_station_patrol_look3]points = p0p0:name = wp00|a=guardp0:flags = 0x1p0:position = -170.93078613281,19.901081085205,-158.97375488281p0:game_vertex_id = 3672p0:level_vertex_id = 599275[zat_gas_station_patrol_walk3]points = p0p0:name = wp00p0:flags = 0x1p0:position = -170.87844848633,20.028577804565,-161.26043701172p0:game_vertex_id = 3672p0:level_vertex_id = 599272[zat_gas_station_patrol_look4]points = p0p0:name = wp00|a=guardp0:flags = 0x1p0:position = -163.19924926758,20.029188156128,-166.2618560791p0:game_vertex_id = 3672p0:level_vertex_id = 615065[zat_gas_station_patrol_walk4]points = p0p0:name = wp00p0:flags = 0x1p0:position = -165.72045898438,20.02819442749,-166.74816894531p0:game_vertex_id = 3672p0:level_vertex_id = 609320[zat_gas_station_patrol_look5]points = p0,p1p0:name = wp00|a=hidep0:flags = 0x1p0:position = -159.47149658203,19.776128768921,-178.98678588867p0:game_vertex_id = 3672p0:level_vertex_id = 622267p1:name = wp01|a=hidep1:flags = 0x1p1:position = -152.04862976074,20.225852966309,-175.70111083984p1:game_vertex_id = 3672p1:level_vertex_id = 638596p1:links = p0(1)[zat_gas_station_patrol_walk5]points = p0p0:name = wp00p0:flags = 0x1p0:position = -157.36337280273,20.028509140015,-172.5984954834p0:game_vertex_id = 3672p0:level_vertex_id = 626645[zat_gas_station_patrol_look6]points = p0,p1p0:name = wp00|a=hidep0:flags = 0x1p0:position = -172.7536315918,19.877557754517,-177.65606689453p0:game_vertex_id = 3672p0:level_vertex_id = 594849p1:name = wp01|a=hidep1:flags = 0x1p1:position = -176.77577209473,19.8899269104,-172.32081604004p1:game_vertex_id = 3672p1:level_vertex_id = 586539p1:links = p0(1)[zat_gas_station_patrol_walk6]points = p0p0:name = wp00p0:flags = 0x1p0:position = -168.58984375,20.029529571533,-169.03833007813p0:game_vertex_id = 3672p0:level_vertex_id = 603661[zat_gas_station_patrol_walk7]points = p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11p0:name = wp00|a=patrolp0:flags = 0x1p0:position = -177.95030212402,19.892816543579,-170.10719299316p0:game_vertex_id = 3672p0:level_vertex_id = 585261p0:links = p2(1)p1:name = wp01|a=patrolp1:flags = 0x2p1:position = -178.44303894043,20.010766983032,-188.76034545898p1:game_vertex_id = 3672p1:level_vertex_id = 583941p1:links = p0(1)p2:name = wp02|a=patrolp2:flags = 0x4p2:position = -178.22425842285,20.006406784058,-191.03433227539p2:game_vertex_id = 3672p2:level_vertex_id = 583938p2:links = p4(1)p3:name = wp03|a=patrolp3:position = -155.91751098633,19.15784072876,-189.83374023438p3:game_vertex_id = 3673p3:level_vertex_id = 629541p3:links = p1(1)p4:name = wp04|a=patrolp4:flags = 0x8p4:position = -155.81336975098,19.577337265015,-192.12979125977p4:game_vertex_id = 3673p4:level_vertex_id = 629538p4:links = p6(1)p5:name = wp05|a=patrolp5:position = -153.88307189941,19.837575912476,-170.7787322998p5:game_vertex_id = 3672p5:level_vertex_id = 634065p5:links = p3(1)p6:name = wp06|a=patrolp6:position = -153.67362976074,19.787631988525,-168.28823852539p6:game_vertex_id = 3672p6:level_vertex_id = 634069p6:links = p8(1)p7:name = wp07|a=patrolp7:position = -153.6607208252,19.696378707886,-159.70063781738p7:game_vertex_id = 3672p7:level_vertex_id = 634081p7:links = p5(1)p8:name = wp08|a=patrolp8:position = -153.5884552002,19.616180419922,-158.62452697754p8:game_vertex_id = 3672p8:level_vertex_id = 635611p8:links = p10(1)p9:name = wp09|a=patrolp9:position = -175.44000244141,19.932542800903,-159.28170776367p9:game_vertex_id = 3672p9:level_vertex_id = 589203p9:links = p7(1)p10:name = wp10|a=patrolp10:position = -175.66333007813,19.933841705322,-157.82580566406p10:game_vertex_id = 3672p10:level_vertex_id = 589206p10:links = p11(1)p11:name = wp11|a=patrolp11:position = -175.61622619629,19.892559051514,-166.17030334473p11:game_vertex_id = 3672p11:level_vertex_id = 589194p11:links = p9(1)[zat_gas_station_camp3_center]points = p0p0:name = wp00p0:position = -162.73413085938,19.791074752808,-154.43911743164p0:game_vertex_id = 3672p0:level_vertex_id = 616516[zat_gas_station_movie_look]points = p0p0:name = wp00|a=sit_assp0:flags = 0x1p0:position = -164.66107177734,20.028505325317,-163.32861328125p0:game_vertex_id = 3672p0:level_vertex_id = 612214[zat_gas_station_movie_walk]points = p0p0:name = wp00p0:flags = 0x1p0:position = -163.43371582031,20.028532028198,-163.29096984863p0:game_vertex_id = 3672p0:level_vertex_id = 615070[zat_gas_station_leader_look]points = p0p0:name = wp00|a=wardp0:flags = 0x1p0:position = -169.37171936035,20.028509140015,-165.0013885498p0:game_vertex_id = 3672p0:level_vertex_id = 602222[zat_gas_station_leader_walk]points = p0p0:name = wp00p0:flags = 0x1p0:position = -171.01541137695,20.028509140015,-166.41958618164p0:game_vertex_id = 3672p0:level_vertex_id = 599270


    Ogólna zasada tworzenia punktu jest następująca: w nawias kwadratowy wpisujemy nazwę naszego smart terrain'a połączoną z nazwą punktów, osobno dla path_walk i path_look. Wpis nie może zawierać pustych znaków jak spacja czy tabulacja, elementy tworzące całość oddzielamy poprzez _ ("podkreślnik dolny").
    Przykład:

    [zat_gas_station_patrol_look1][zat_gas_station_patrol_walk1]
    gdzie:
    zat_gas_station - nowo utworzony smart terrain (Etap II, pkt. 3 poradnika).
    patrol_look1 - punkt określony w pliku gulag_*.ltx wyznaczający kierunek patrzenia (Etap II, pkt. 6 poradnika).
    patrol_walk1 - punkt wyznaczający zajmowaną pozycję przez NPC'a, zdefiniowany w gulag_*.ltx (Etap II, pkt. 6 poradnika).
    points = p0,p1 oznacza, iż NPC wodzi wzrokiem od pkt. p0 do p1 po osiągnięciu którego poprzez wpis:

    p1:links = p0(1)
    kieruje wzrok do pierwotnej pozycji, po czym rozpoczyna się cały schemat.
    Wg. powyższych punktów trasy patrolowej, NPC przemieszcza się następująco :
    p00 -> p02 -> p04 -> p06 -> p08 -> p10 -> p11 (powrót) -> p09 -> p07 -> p05 -> p03 -> p01 -> p00 (cykl rozpoczyna się na nowo)

    W/w schemat trasy zaznaczono na załączniku (I Etap poradnika, pkt.2), gdzie na czerwono oznaczono trasę wiodącą do celu, powrót natomiast na pomarańczowo.

    W powyższym pliku występują również wpisy (najczęściej spotykane):

    wp00|a=hide - animacja przykucniętego NPC w zajmowanym punkcie.wp00|a=ward - animacja NPC z rękoma założonymi do tyłu.wp00|a=guard - animacja dla strażnika.wp00|a=patrol - amimacja jednostki patrolującej.wp00|a=sit_ass - animacja stalkera siedzącego.wp00|a=binocular - animacja stalkera obserwującego zadany punkt lornetką (czas obserwacji - cały cykl).wp00|a=bar_fas - animacja stalkerów opierających się o stolik.wp00|a=sleep - animacja śpiącego stalkera.wp00|a=sneak - animacja skradającego się stalkeraname02|a=assault - animacja NPC szturmującego. (patrz wpisy analogiczne w plikach way_*ltx).

    Aby lornetka była dostępna dla obserwatora w sekcji spawnowanej postaci tj. pliku alife_*.ltx należy dodać wpis:

    [spawn]wpn_binoc

    Wówczas zostanie ona zespawnowana w ekwipunku postaci (patrz pkt.8.1 - dodawanie NPC). Ów wpis należy wkomponować pomiędzy parametry - jak w przykładzie poniżej:

    [smart_terrains]zat_gas_station = true[spawn]wpn_binocEND
    Animacja w każdym punkcie może być inna, jednakże dla niezmieniającego pozycji NPC warto obrać tylko jedną. Jeśli tworzymy skomplikowaną trasę NPC, np. szturm wrogiej bazy, wówczas możemy dla poszczególnych punktów trasy obrać animacje:
    a=binocular|t=20000 (obserwację obiektu w czasie t) a=assault (szturm), a=sneak (podkradanie się). Stworzenie takiej trasy jest bardzo czasochłonne - wytrwałym polecam spróbować, wcześniej poprzez analogię sprawdzając jak skonstruowano schemat takiej trasy w plikach way_*ltx z niemodowanego stalkera.
    * - nazwa mapy. Przykłady animacji stalkerów w funkcji schematu obozowiska ilustruje poniższy załącznik:
    post-3466-0-91549600-1378840489_thumb.pn
    position, game_vertex_id, level_vertex_id - koordynaty i punkty wierzchołkowe, wyznaczone uprzednio - patrz Etap I, pkt. 2 poradnika. Pomiędzy wpisami zachowany jest 2-wierszowy odstęp!
  • Mamy już niemal wszystko z wyjątkiem NPC'ów, których musimy od podstaw skonfigurować. Nasz smart terrain obsługuje 10 stalkerów i tyle muszę stworzyć jednostek, by wykorzystać pełen potencjał obozowiska. Podam jeden przykład wg. którego postępujemy - pozostałych NPC'ów dodaje się analogicznie, zmieniając wg. uznania model postaci, pozycję rankingową, posiadaną kwotę, dźwięk rozmów, posiadaną broń etc. Do podstawowej konfiguracji NPC potrzebujemy następujących plików:
    - alife_*.ltx [zdekompilowany plik all.spawn]- character_desc_*.xml [gamedataconfiggameplay]- npc_profile.xml [gamedataconfiggameplay]- game_story_ids.ltx [gamedataconfig]- spawn_sections.ltx [gamedataconfigcreatures]
    * - nazwa mapy
    8.1. Do pliku alife_*.ltx (w przykładzie alife_zaton.ltx) dodaję sekcję spawnowanego NPC. 

    [11629]; cse_abstract propertiessection_name = stalkername = zaton_stalker1position = -178.02299499512,20.006784439087,-199.22261047363direction = 0,0,0; cse_alife_trader_abstract propertiesmoney = 10000character_profile = zat_leader; cse_alife_object propertiesgame_vertex_id = 3671distance = 4.19999980926514level_vertex_id = 585219object_flags = 0xffffffbfcustom_data = <<END[smart_terrains]zat_gas_station = trueENDstory_id = 5481; cse_visual propertiesvisual_name = actorszaton_leader; cse_alife_creature_abstract propertiesg_team = 0g_squad = 1g_group = 5health = 1dynamic_out_restrictions =dynamic_in_restrictions =upd:health = 1upd:timestamp = 0upd:creature_flags = 0upd:position = -178.02299499512,20.006784439087,-199.22261047363upd:o_model = 0upd:o_torso = 0.00313752260990441,0.0623208954930305,0upd:g_team = 0upd:g_squad = 1upd:g_group = 5; cse_alife_monster_abstract propertiesupd:next_game_vertex_id = 65535upd:prev_game_vertex_id = 65535upd:distance_from_point = 0upd:distance_to_point = 0; cse_alife_human_abstract propertiespredicate5 = 1,2,2,2,2predicate4 = 2,0,1,2; cse_ph_skeleton propertiesupd:start_dialog =; se_stalker properties


    Omówienie parametrów sekcji:
    [11629] - nr. dodawanego obiektu (nie może się powtarzać dla całego pliku).

    section_name = stalker
    wpis stały przy dodawaniu NPC, nie wpływa na frakcję!
    name - nazwa dodawanego obiektu, która dla każdego obiektu powinna być inna.
    position - koordynaty X,Y,Z
    direction - obrót obiektu po zespawnowaniu.
    money - ilość posiadanej gotówki.
    character_profile - jest to przyporządkowanie postaci określonego profilu, definiowanego szczegółowo w pliku character_desc_*.xml oraz wykorzystywanego w skrypcie (jeśli takowy stworzono) gulag_*.script (w moim przykładzie gulag_escape.script) poprzez funkcję:

    predicate = function(obj_info) return obj_info.story_id == 5481
    (związaną poprzez plik game_story_ids.ltx - omówienie pkt. 8.4) dzięki której wyznaczamy określony typ zadań postaci o zadanym profilu.
    game_vertex_id, level_vertex_id - punkty wierzchołkowe wyznaczone za pomocą "Smartterrain and Waypoint Tools by dez0wave" (patrz etap I, pkt.1 poradnika)
    zat_gas_station = true - wpis określa smart terrain z którego będzie korzystała postać.
    story_id = 5481 - parametr odnoszący się do pliku game_story_ids.ltx [gamedataconfig] omówiony w pkt.8.4
    visual_name - ścieżka do modelu .ogf
    upd:position - parametr określający współrzędne obiektu. Musi być zawsze taki sam jak position.
    pozostałe parametry pozostawić należy domyślnie (tworzenie spawna z uzyciem SDK).

     

    8.2.  Tworzę szczegółowy profil NPC. Plik w którym umieszczam stosowny wpis (zwróć uwagę na nazwę przyporządkowaną do character_profile w pliku alife_*.ltx - w którym została dodana postać) zależny od mapy na której spawnujemy postać. Ponieważ wykorzystywałem pliki gulag_escape.script oraz gulag_escape.ltx - wpis dodaję do [gamedataconfiggameplay] character_desc_escape.xml (jest to sytuacja wyjątkowa - pliki w/w wykorzystałem by skrócić czas przygotowania stalkerskiego obozowiska).

    <!---------------------------Zaton Leader------------------->    <specific_character id="zat_leader" team_default = "1">        <name>Keldorn</name>        <icon>ui_npc_u_stalker_ki_antigas</icon>        <bio>zat_leader</bio>        <class>zat_leader</class>        <community>stalker</community> <terrain_sect>stalker_terrain</terrain_sect>                <rank>810</rank>        <reputation>200</reputation>        <money min="9000" max="10000" infinitive="0"></money>                <visual>actorszaton_leader</visual>        <snd_config>characters_voicehuman_01stalker</snd_config>        <crouch_type>-1</crouch_type>        <supplies>            [spawn] n            wpn_pm n            ammo_9x18_fmj = 1 n		    wpn_val n		    ammo_9x39_ap n            device_torch n    #include "gameplaycharacter_drugs.xml"#include "gameplaycharacter_food.xml"#include "gameplaycharacter_items.xml"        </supplies>#include "gameplaycharacter_criticals_4.xml"            <start_dialog>dm_hello_dialog</start_dialog>        <actor_dialog>dm_cool_info_dialog</actor_dialog>        <actor_dialog>dm_help_wounded_medkit_dialog</actor_dialog>    </specific_character>    <!---------------------------Zaton Leader------------------->


    Opis parametrów sekcji na przykładzie:
    specific_character id - jest to unikalny identyfikator postaci, wykorzystywany w plikach: alife_*.ltx, gulag_*.script, spawn_sections.ltx, game_story_ids.ltx. Ów parametr jest taki sam dla wszystkich wymienionych plików, łącząc różne funkcje składające się na funkcjonowanie NPC o określonym identyfikatorze profilowym.
    <name>Keldorn</name> - nazwa postaci.
    <icon>ui_npc_u_stalker_ki_antigas</icon> - określa jaka ikona postaci będzie wyświetlana podczas przeglądania kontaktów na PDA, rozmów, przeglądania zwłok etc. Odpowiednie konfiguracje położenia ikony można znaleźć w pliku ui_npc_unique.xml [gamedataconfigui]. W tym przypadku gra odczytuje na podst. współrzędnych z w/w pliku - sektor z interesującą nas ikoną zawartą w pliku tekstur ui_npc_unique.dds [gamedatatexturesui]:

    <texture id="ui_npc_u_stalker_ki_antigas" x="330" y="756" width="165" height="108" />
    Zapis j/w oznacza położenie ikony w oddaleniu od osi OX o 330 px. (wartość naliczana od lewej strony pliku ikon) oraz odległość od osi OY o 756 px. (wartość naliczana od górnej części pliku ikon). Położenie mierzone jest do górnej-lewej części ikony. Width (szerokość) i height (wysokość) również mierzone są w pixelach. Znając powyższe wskazówki jesteśmy w stanie określić położenie ikony w pliku oraz stworzyć własną.
    <bio>zat_leader</bio> jest odnoszącym się do biografii parametrem, który zawiera plik [gamedataconfigtextpol] stable_bio_name.xml.
    <class>zat_leader</class> - klasa postaci z uwagi na jej unikalny charakter określona w pliku npc_profile.xml [gamedataconfiggameplay]
    <community>stalker</community> - przynależność frakcyjna. Możemy ustawić dowolną frakcję, jednak musi być ona zawsze zgodna z parametrem npc_community - występującym w pliku gulag_*.script [gamedatascripts] - patrz Etap II, pkt. 5 poradnika (sekcja 3)
    <rank>810</rank> - pozycja rankingowa NPC.
    <reputation>200</reputation> - reputacja NPC'a
    <money min="9000" max="10000" infinitive="0"></money> - zakres min. i max. posiadanej gotówki (gra wybierze wartość z zadanego zakresu).
    <visual>actorszaton_leader</visual> - ścieżka do modelu .ogf, czyli wygląd postaci zgodny z parametrem "visual_name" zdefiniowanym w pliku alife_zaton.ltx.
    <snd_config>characters_voicehuman_01stalker</snd_config> - ścieżka do pliku dźwiękowego wykorzystywanego przez NPC np. w czasie rozmów przy ognisku, zwracania uwagi na podniesioną broń, reakcji na zagrożenie etc.
    <crouch_type>-1</crouch_type> - animacja przykucniętego NPC (obieram wartość defaultową).
    <supplies>..... </supplies> - tag definiuje rodzaj posiadanego przez postać ekwipunku oraz zawiera odnośniki do plików odpowiadających za:
    a). jedzenie (character_food.xml) - wykaz oraz prawdopodobieństwo zespawnowania w ekwipunku stalkera:
    bread = 1, prob=0.3 nkolbasa = 1, prob=0.3 nvodka = 1, prob=0.2 nenergy_drink = 1, prob=0.5 n
    b). środki medyczne (character_drugs.xml)
    medkit = 1, prob=0.2 nbandage = 1, prob=0.4 n
    c). przedmioty dodatkowe (character_items.xml)
    harmonica_a = 1, prob=0.7 nguitar_a = 1, prob=0.7 ndevice_torch = 1, prob=0.5 n
    W/w pliki zlokalizowane są w [gamedataconfiggameplay]. Szereg wpisów sekcji supplies odpowiedzialnych za ekwipunek postaci:
    wpn_pm n               <!------ Broń krótka, Makarovammo_9x18_fmj = 1 n    <!------ Amunicja kalibru 9x18 mmwpn_val n              <!------ Broń podstawowa, AS Valammo_9x39_ap n         <!------ Amunicja kalibru 9x39 mmdevice_torch n         <!------ Latarka na wyposażeniu
    <start_dialog></start_dialog> - pomiędzy tag dodawany jest dialog postaci z Naznaczonym. Odpowiednio skonstruowany skrypt połączony z dialogiem oferuje postaci mozliwość zlecania zadań, naprawy broni, handlu etc. To dialogi są kluczowym elementem rozwoju fabułu - jeśli chcemy uczynić postać kimś więcej niż tylko wartownikiem, modyfikujemy tą cześć sekcji poprzez dodanie nowego dialogu, którego konstrukcja to temat innego poradnika. Częściowo - na przykładzie zlecania zadań jest to omówione w tym poradniku (Link). Mój przykład zawiera standardowe dialogi - ponieważ tematem tutoriala jest tworzenie obozu - nie dialogów.

     

    8.3.Tworząc nowego NPC, uzupełniamy plik npc_profile.xml [gamedataconfiggameplay] o wpis:
    <character id="zat_leader">    <class>zat_leader</class>    <specific_character>zat_leader</specific_character></character>
    Który jest zgodny z występującym w character_desc_escape.xml parametrem <class> (patrz profil NPC - pkt. 8.2)

     

    8.4. Kolejnym plikiem, który musimy uzupełnić jest game_story_ids.ltx [gamedataconfig]:

    5481	    = "zat_leader"
    Numer musi być taki sam jak występujący w parametrze story_id = 5481,
    który zawiera sekcja postaci spawnowanej w pliku alife_zaton.ltx (patrz pkt. 8.1). Numeracji nie wolno dublować, w przeciwnym wypadku rozpoczęcie gry zakończy się wypadem na pulpit! Zawsze dostosowujemy ją do zawartości pliku.

     

    8.5. Ostatni z plików potrzebnych do sfinalizowania konfiguracji NPC jest spawn_sections.ltx [gamedataconfigcreatures].Dodajemy wpis, którego kluczowa zawartość odnosi się do identyfikatora profilowego (unikalnego dla każdej postaci). W moim przypadku jest to "zat_leader"
    [zat_leader]:stalker$spawn = "respawnzat_leader"character_profile = zat_leaderspec_rank = veterancommunity = stalker
    Jedyne na co warto zwrócić uwagę to spec_rank, dostosowanie do rangi postaci określonej przez parametr <rank> zawarty w pliku character_desc_*.xml [character_desc_escape.xml]. - Tutorial, Etap II - pkt. 8.2. Dostosowujemy wg. pliku _g.script [gamedatascripts] gdzie:
    - novice - ranga od 0 do 299- stalker - ranga od 300 do 599- veteran - ranga od 600 do 899- master - ranga powyżej 900.

Wszystkie wprowadzone zmiany zapisujemy, przy czym te wprowadzone do plików  alife_*.ltx oraz way_*.ltx musimy poddać kompilacji, by zapisane sekcje znalazły się w pliku all.spawn!

 

 

Jeśli zrobiliśmy wszystko zgodnie z tutorialem - możemy sobie pogratulować cierpliwości sprawdzając efekt naszej pracy, który w przypadku mojej bazy prezentuje się następująco.

 

http://www.youtube.com/watch?v=5nqS-Kr6268

 

 

 

II. Etap wykonawczy - przypadki szczególne.

 

Przypadek szczególny należy rozpatrywać w kontekście braku dostępności pozycji - przez NPC np. dachy budynków w związku z czym, taka jednostka nie może mieć przyporządkowanego smart terraina z uwagi na niedostępność docelowej pozycji (path) - wynikającej z braku siatki AI wg. której NPC odnajduje drogę do celu.

 

Tworzenie snajpera:
Moim zamiarem jest dodanie snajpera, którego zajmowana pozycja mieści się na zniszczonym moście na Kordonie. Ponieważ jest to miejsce niedostępne dla stalkerów - z uwagi na znajdujące się tam wagony oraz siatkę - snajper musi być zespawnowany w miejscu docelowym (w punkcie do którego nie byłby w stanie dojść), ale uwaga - w tej sytuacji nie może zostać przypisany smart terrain'owi, którego punkty terenowe konieczne dla stworzenia zadań powinny być osiągalne dla stworzonych jednostek, innymi słowy - taki stalker nie zająłby pozycji z uwagi na brak dojścia na most - doszło by do wylotu na pulpit! Aby tego uniknąć jest prosty sposób:

 

  • W pliku powstałym po dekompilacji all.spawn, zależnym od miejsca dodawania - w moim przypadku alife_l01_escape.ltx, umieszczam sekcję snajpera:

    [2081]; cse_abstract propertiessection_name = stalkername = esc_sniper01position = 41.840690612793,20.0822887420654,153.950622558594direction = 0,0,0; cse_alife_trader_abstract propertiesmoney = 5000character_profile = esc_soldier_specnaz; cse_alife_object propertiesgame_vertex_id = 94distance = 28level_vertex_id = 308460object_flags = 0xffffffbbcustom_data = <<END[logic]active = camper[camper]path_walk = esc_snip_spec_1_standpath_look = esc_snip_spec_1_lookradius = 7sniper = true[smart_terrains]none = trueEND; cse_visual propertiesvisual_name = actorssoldiersoldier_antigas; cse_alife_creature_abstract propertiesg_team = 0g_squad = 1g_group = 6health = 1dynamic_out_restrictions =dynamic_in_restrictions =upd:health = 1upd:timestamp = 0upd:creature_flags = 0upd:position = 41.840690612793,20.0822887420654,153.950622558594upd:o_model = 0upd:o_torso = 0,0,0upd:g_team = 0upd:g_squad = 1upd:g_group = 6; cse_alife_monster_abstract propertiesupd:next_game_vertex_id = 65535upd:prev_game_vertex_id = 65535upd:distance_from_point = 0upd:distance_to_point = 0; cse_alife_human_abstract propertiespredicate5 = 2,0,1,2,2predicate4 = 2,2,2,0; cse_ph_skeleton propertiesupd:start_dialog =; se_stalker properties


    Parametry sekcji NPC zostały omówione w pkt. 8.1
    To co wyróżnia w/w jednostkę to wpisy:

    [logic]active = camper[camper]path_walk = esc_snip_spec_1_standpath_look = esc_snip_spec_1_lookradius = 7sniper = true
    Oznacza to, iż nasz NPC korzysta z schematu [camper], który ma określone punkty:
    zajmowanej pozycji - path_walk
    kierunku patrzenia - path_look
    W/w współrzędne należy dodać do pliku way_*.ltx (w moim przykładzie: way_l01_escape.ltx).
    sniper = true - animacja snajpera.
    [smart_terrains]none = true
    Powyższy wpis oznacza, iż NPC nie korzysta z żadnego smart terrain'a (utrzymuje jednak pozycję wg. punktów).

  • Do pliku way_l01_escape.ltx dodajemy współrzędne o takiej samej nazwie jak dla w/w punktów schematu [camper] path_walk oraz path_look. Nazwę identyfikującą współrzędne należy ująć w nawias kwadratowy - patrz poniżej:


    [esc_snip_spec_1_look]points = p0,p1p0:name = wp01|a=hidep0:flags = 0x1p0:position = 69.3523788452148,2.4903564453125,83.3903884887695p0:game_vertex_id = 161p0:level_vertex_id = 359732p0:links = p1(1)p1:name = wp02|a=hidep1:flags = 0x1p1:position = -24.389612197876,1.9730464220047,98.7673110961914p1:game_vertex_id = 86p1:level_vertex_id = 252731p1:links = p0(1)[esc_snip_spec_1_stand]points = p0p0:name = wp00p0:flags = 0x1p0:position = 41.841381072998,20.0829124450684,153.915618896484p0:game_vertex_id = 94p0:level_vertex_id = 308460


    Z powyższych punktów terenowych korzysta wcześniej przypisany snajperowi schemat [camper].

  • Tak wprowadzone dane zapisujemy - kompilując plik all.spawn, umieszczając go następnie w gamedataspawns.
  • Następnie konfigurujemy profil postaci - dodając do plików stosowne sekcje, wg. pkt. poradnika 8 do 8.5

    character_profile = esc_soldier_specnaz
    w/w wpis esc_soldier_specnaz - jest oczywiście unikalnym identyfikatorem postaci - o czym należy pamiętać tworząc NPC'ów.
  • Po dodaniu potrzebnych plików, sprawdzamy efekt naszej pracy.

Schemat snajpera - pomijając fakt braku snajperki i ghillie suit'a - elementy które można dodać, nasz NPC prezentuje się następująco.

 

post-3466-0-03906500-1377112089_thumb.jp

 

Prawa autorskie na podstawie regulaminu, pkt.1.6. - The Emperor, wyłączność: StalkerTeam.

_____________________________

Autor: The Emperor dla StalkerTeam

  • Dodatnia 14
Odnośnik do komentarza
Udostępnij na innych stronach

  • 1 miesiąc temu...
  • 2 tygodnie później...

@The Emperor - poprosiłbym o tutorial pod CoP. Zadania ogarnąłem, ale spawnowania NPC W CoP nie. To znaczy spawnować NPC umiem (cholera, twórcy CoP spawn i funkcje NPC przenieśli w skrypty :verymad: ) ale NPC łazi tam, gdzie mu się zachce (miał stać w jednym miejscu). Proszę więc o napisanie tego od początku (i o to np. jak dodać dialog do nowo zespawnowanej postaci, jak zmienić ją na handlarza, przewodnika). Nie musisz tego pisać od razu, ale jak będziesz miał czas. Pozdro.

Edytowane przez StalkerCell
Odnośnik do komentarza
Udostępnij na innych stronach

@StalkerCell

W tej chwili z powodu braku czasu nie jestem w stanie napisać poradnika, ale żeby nie zostawić Cię bez odpowiedzi - jest poradnik odnośnie skryptowego dodawania NPC wraz ze smart terrainem pod CoP (wersja rus.). Sprawdź ten link, powinien wiele wyjaśnić.

  • Dodatnia 1
Odnośnik do komentarza
Udostępnij na innych stronach

  • Meta zablokował(a) ten temat
Gość
Ten temat został zamknięty. Brak możliwości dodania odpowiedzi.
×
×
  • Dodaj nową pozycję...

Powiadomienie o plikach cookie

Korzystając z tej strony, zgadzasz się na nasze Warunki użytkowania.