SoC Tutorial
Tytułem wstępu:
Niech obszerność poradnika nie zniechęca Cię - do tworzenia questu!. Aby kompleksowo opisać poszczególne etapy tworzenia zadań, nie wystarczy kilka punktów, toteż zachęcam do lektury. Poradnik umożliwia stworzenie nowego questu zarówno w Shoc jak i w Solijance, na podstawie której został napisany.
Zanim zaczniemy pracę z tworzeniem zadań, będzie nam potrzebny program/skrypt umożliwiający pokazanie game_vertex_id oraz level_vertex_id, niezbędnych dla spawnu obiektu.
Pobieramy to narzędzie modderskie:
http://sdk.stalker-game.com/en/images/d/d7/Smartterrain_and_Waypoint_Tools_by_dez0wave.zip
Po wypakowaniu - zawartość folderu: save_pos_patrol - wrzucamy do naszego gamedata.
Sposób użytkowania:
- [*]wychodzimy do menu gry i wciskamy klawisz
Z - który aktywuje menu z opcją nadania nazwy dla 1 punktu. [*]lub naciskamy klawisz X - aktywujący menu, umożliwiające wpisania nazwy dla wielu punktów, co jest przydatne zwłaszcza dla tworzenia smart terrain’a.
Dane o punkcie zapisują się w logu z dużą dokładnością. Jest to wygodne o tyle, iż nie musimy spisywać z monitora długiego ciągu liczb. Wystarczy iż skopiujemy wartości, które nas interesują.
Tak przedstawia się menu powyżej omówionego narzędzia.
________________________________
Część |. - znajdź przedmiot.
Aby ułatwić sobie realizację poszczególnych punktów niniejszego opracowania, potrzebną ilość plików oraz ich wzajemne powiązanie - warto zapoznać się ze screenem:
- [*]Potrzebny będzie plik skryptu, który zawiera funkcję spawnu przedmiotu. (będziemy definiować funkcję). Tworzymy plik
tutorial.script i umieszczamy w katalogu gamedata/scripts. Jeśli ktoś wcześniej nie miał do czynienia z plikami, wystarczy, iż zmieni rozszerzenie z .txt na .script - nadając nazwę plikowi.
W pliku na potrzeby zadania utworzymy 3 funkcje, jednakże aby unaocznić, jakie powiązania posiadają pliki, będziemy stopniowo dodawać funkcje.
W nowo utworzonym pliku o nazwie j/w. umieszczamy funkcję:
-- Tutorialowy skrypt.function spawn_kanister()alife():create("explosive_mobiltank",vector():set(-244.069,-19.549,-128.138),12825,8)end
Funkcja służy zespawnowaniu obiektu, w naszym przykładzie będzie to kanister z benzyną czyli explosive_mobiltank [katalog weapons]
Współrzędne w funkcji - kolejno: (poniższego wpisu nie dodawaj do skryptu)
X: -244.069Y: -19.549Z: -128.138level_vertex_id: 12825game_vertex_id: 8
[*]Potrzebny będzie plik dialogu, zawierający wpis aktywujący funkcję - character_desc_escape.xml [gamedataconfiggameplay] do którego musimy dodać nowy dialog, w naszym przykładzie Wilk będzie zlecał zadanie na przyniesienie kanistra do zasilenia generatora - stąd w/w plik. Jeśli zależy nam na innej postaci, wpis dotyczący dialogu dodajemy do pliku .xml - właściwego dla tejże postaci. [*]Znajdujemy sekcję odpowiedzialną za konfigurację Wilka, tj. esc_wolf. Interesują nas dialogi, przechodzimy do wpisu poniżej frazy , znajdziemy tam następujące wpisy:
<start_dialog>escape_lager_volk_talk</start_dialog> <start_dialog>dm_hello_dialog</start_dialog> <actor_dialog>dm_cool_info_dialog</actor_dialog> <actor_dialog>dm_help_wounded_medkit_dialog</actor_dialog> <actor_dialog>tm_wolf_dialog</actor_dialog> <actor_dialog>tm_wolf_reward</actor_dialog></specific_character>
Dodajemy do powyższego nowy dialog, czyli poniższy wiersz:
<actor_dialog>explosive_dialog</actor_dialog>
Dialog rozpoczyna - I część zadania, w której przedmiot będzie spawnowany poprzez skrypt oraz do PDA zostanie dodany stosowny wpis w zakładce “zadania aktywne”.
[*]
Konstruujemy drzewo dialogowe zawierające “explosive_dialog”, stosowny wpis dodajemy w pliku dialogs_escape.xml [gamedataconfiggameplay]
<dialog id="explosive_dialog"> <dont_has_info>kanister_done</dont_has_info> <dont_has_info>kanister_start</dont_has_info> <phrase_list> <phrase id="0"> <text>explosive_dialog_0</text> <next>1</next> </phrase> <phrase id="1"> <text>explosive_dialog_1</text> <action>tutorial.spawn_kanister</action> <next>2</next> </phrase> <phrase id="2"> <text>explosive_dialog_2</text> <give_info>kanister_start</give_info> <action>dialogs.break_dialog</action> <action>tutorial.gasoline_have</action> </phrase> </phrase_list> </dialog>
gdzie:
<dont_has_info>kanister_done</dont_has_info>
□ to jeden z warunków - pojawienia się dialogu. Warunek jest spełniony, gdy informacja “kanister_done”, która oznacza - wypełnienie zadania z kanistrem - nie zostanie dodana do PDA.
<dont_has_info>kanister_start</dont_has_info>
□ drugi warunek pojawienia się dialogu w menu, oznacza iż nie mając wpisu “kanister_start” - mamy widoczny (dostępny) dialog. Zasada podobna j/w. - brak określonych infoportion - generuje dialog. Czemu ma to służyć, hmm? - otóż patrząc na drzewo dialogowe z pkt.4 mamy wpis:
<give_info>kanister_start</give_info>
□ drzewo dodaje informację “kanister_start” do PDA - jeśli doprowadzimy dialog do końca, wówczas złamiemy warunek :
<dont_has_info>kanister_start</dont_has_info>
czyli będziemy mieli infoportion - i bardzo dobrze - bowiem dialog już się nie powtórzy - tylko zniknie, poprzez złamanie jednego z warunków. Chcąc pozbyć się z menu dialogowego - danej rozmowy, która już jest nieaktualna a dotyczy np. wykonanego zadania - musimy doprowadzić do takiego układu infoportion, aby warunki nie zostały powtórzone (warunki jednorazowe), czyli dodajemy poprzez <give_info> odpowiedni wpis, który stoi w sprzeczności z <dont_has_info> - czyli brakiem informacji zdefiniowanej w początkowym ustawieniu drzewa dialogowego.
Jeśli przykładowo pominę :
<dont_has_info>kanister_start</dont_has_info>
to warunek 1 zawsze będzie spełniony - ponieważ jest nim brak wpisu, a zatem dialog
będzie widoczny po zakończeniu zadania, stwarzając możliwość jego zdublowania. Bardzo ważny jest sposób w jaki skrypt jest aktywowany, przyjrzyjmy się wpisowi tutorial.spawn_kanister - wpis jest podzielony na 2 części, rozdziela kropka. Specjalnie wyróżniłem podział, również w pkt. 1 poradnika.
□ Część 1 - tutorial - to nazwa pliku z rozszerzeniem .script, który zawiera funkcję wywoływaną. (pkt 1. poradnika) - nowo utworzony plik skryptu (nie wpisujemy rozszerzenia pliku skryptu)
□ część 2 - spawn_kanister - ponieważ plik może zawierać wiele funkcji, ten wpis konkretyzuje żądane działanie, czyli spawn obiektu explosive_mobiltank. W tym przykładzie spawn następuje przy explosive_dialog_1, możemy oczywiście stworzyć bardziej rozbudowany dialog i wpis dodać w innej sekcji drzewa.
<give_info>kanister_start</give_info>
□ informacja dodana do PDA, infoportion omówiony dalej.
<action>dialogs.break_dialog</action>
□ w/w wpis ucina dialog, który byłby zapętlany - odwołanie do dialogs.script, funkcja: break_dialog
<action>tutorial.gasoline_have</action>
□****aktywuje funkcję, którą musimy utworzyć w pliku z pkt.1
Omówione w pkt.5 - gasoline_have.
<dialog id="explosive_dialog">
□ identyfikator dialogu, dodany w pliku character_desc_escape.xml, w naszym przykładzie, zgodnie z pkt 3.
□ explosive_dialog_0/explosive_dialog_1/explosive_dialog_2 - to odniesienia do tekstu zawartego w katalogu: [gamedataconfigtextpol] - pliku: stable_dialogs_escape.xml.
Uwaga: tworząc drzewo dialogowe należy zachować szyk tagów je tworzących, jeśli chcemy wkomponować wpisy pomiędzy istniejące już sekcje. Dodajemy wpisy pomiędzy kończącej, a <dialog id=" - następnej sekcji. - patrz pierwotne konfiguracje rzeczonego pliku.
[*]
Zgodnie z uwagą dotyczącą kolejnej funkcji tj. tutorial.gasoline_have
Do pliku tutorial.script, dodajemy pod poprzednią funkcją z pkt.1 - wpis, który powoduje informowanie gracza o zaliczeniu części zadania, gdy questowy item znajdzie się w ekwipunku.
-- dla infoportion_havefunction gasoline_have(task, objective)if db.actor ~= nil thenreturn db.actor:object("explosive_mobiltank") ~= nilendreturn falseend
[*]
Do pliku stable_dialogs_escape.xml [gamedataconfigtextpol], musimy dodać odniesienia: explosive_dialog_0, explosive_dialog_1, explosive_dialog_2 , które zdefiniowaliśmy poprzednio w 4 pkt. poradnika - tworząc “szkielet dialogowy”, ten rodzaj plików odpowiada za czytany tekst.
<string id="explosive_dialog_0"> <text>Mam wrażenie, ze coś cię gryzie?</text></string><string id="explosive_dialog_1"> <text>Skoro emocje mam wypisane na twarzy...jest sprawa, trzeba znaleźć kanister z benzyną do zasilenia agregatu w wiosce, moi ludzie są osłabieni po walce z bandytami, ale Ty wyglądasz na pełnego sił i potrzebującego pieniędzy, więc jak będzie, hmm?</text></string><string id="explosive_dialog_2"> <text>W porządku, zdobędę ten kanister!</text></string>
____________________________________
Część ||. - przynieś przedmiot.
[*]
Tworzymy infoportion - jest to wpis bądź zbiór wpisów, które pozwalają na umiejscowienie zadania w konkretnym momencie fabuły jak również warunkujące pojawienie się zadania i jego usunięcie z menu dialogu postaci. Ponieważ omawiamy przykład dotyczy zadania na Kordonie, potrzebny plik to: info_l01escape.xml [gamedataconfiggameplay] dodajemy infoportions do w/w, czyli wpis poniższy kopiujemy.
<!-- Tutorial_test --><info_portion id="kanister_start"><task>zadanie_testowe</task></info_portion> <info_portion id="kanister_have"></info_portion><info_portion id="kanister_done"></info_portion><!-- Tutorial_test -->
<!– sekcje które są w ten sposób oznaczone, nie są wykorzystywane, można ich używać do komentowania, oznaczania zadań etc.
info_portion id
□ odnosi się do wpisu (pkt. 4 poradnika -patrz: szkielet dialogowy). <give_info>kanister_start</give_info>, ta sekcja jest dodana w pliku dialogs_escape.xml. Pozostałe wpisy kanister_have oraz kanister_done stanowią istotny element poniższych wpisów (pkt.8), dlatego omówię w następnym punkcie poradnika - w kontekście przykładu.
Gdzie:
□ “kanister_start” - wpis służący warunkowaniu pojawienia się zadania.
□ “kanister_have” - wpis służący warunkowaniu pojawienia się zadania w odniesieniu do posiadania przedmiotu w ekwipunku, zgodnie ze zdefiniowaną funkcją - pkt.5
□ “kanister_done” - wpis służący warunkowaniu pojawienia się zadania w odniesieniu do jego zakończenia, będziemy definiować ostatnią funkcję (pkt.11) warunkującą zakończenie misji. W/w sekcje są ściśle związane z plikiem poniższym.
[*]
Do pliku tasks_escape.xml [gamedataconfiggameplay] dodajemy wpis:
<!--Test dot. wpisów w PDA--> <game_task id="zadanie_testowe"> <title>Znaleźć kanister z benzyną</title> <objective> <text>Trzeba poszukać benzyny dla agregatu w wiosce</text> <icon>ui_iconsTotal_find_item</icon> <infoportion_complete>kanister_done</infoportion_complete> <article>opis_zadania_testowego</article> </objective> <objective> <text>Trzeba poszukać benzyny dla agregatu w wiosce</text> <icon height="50" width="50" x="100" y="50">uiui_icons_task</icon> <function_complete>tutorial.gasoline_have</function_complete> <infoportion_set_complete>kanister_have</infoportion_set_complete> </objective> <objective> <text>Dostarcz kanister Wilkowi</text> <map_location_type hint="volk">blue_location</map_location_type> <object_story_id>Escape_novice_lager_volk</object_story_id> <infoportion_complete>kanister_done</infoportion_complete> </objective> </game_task><!--Test-->
W/w sekcja jest kluczowa dla infoportions, ponieważ wiąże określony warunek (wpisy -pkt.7 poradnika) z funkcjami, które definiowaliśmy w pkt. 1 poradnika.
Gdzie:
□ game_task id - dotyczy infoportion “kanister_start” - patrz pkt.7
□ title - to oczywiście tytuł zadania w PDA.
□ text - opis zadania w PDA.
□ icon - ikona wyświetlana w PDA np. inną mamy dla zadania zabić stalkera, inną dla znaleźć artefakt etc. Ikony znajdziemy w ui_iconstotal.dds [gamedatatexturesui]
□ infoportion_complete - wiążące wpis “kanister_done” z funkcją wykonania questu.
□ article - jest to opis szczegółowy, który pojawia się po rozwinięciu zadania w PDA.
□ icon height=“50” width=“50” x=“100” y="50 - definiuje położenie ikony z pliku ui_iconstotal.dds - o wartość odsunięcia 100 px w osi X oraz 50 w osi Y a także wysokość/szerokość ikony na 50 px.
□ function_complete - odniesienie do tutorial.script i funkcji gasoline_have, którą dodaliśmy w pkt. 5 poradnika.
□ infoportion_set_complete - wiąże infoportion kanister_have, z sprawdzeniem posiadania przedmiotu zadania - w ekwipunku i info. zwrotnego do PDA (pkt.7 połączony z pkt.1 poprzez funkcję gasoline_have.
□ map_location_type - znacznik dla postaci (mapa - PDA), dla której wykonujemy zadanie.
□ object_story_id - jest to odniesienie do pliku game_story_ids.ltx, w którym jest zapisany zleceniodawca - w naszym przykładzie - Wilk:
006 = "Escape_novice_lager_volk"
Jeśli chcemy dodać właściwy wpis, musimy odszukać ją w pliku w/w. [*]
Ponownie do pliku dialogu dialogs_escape.xml [gamedataconfiggameplay] dodajemy wpis, który będzie odpowiedzialny za 2 etap zadania, czyli rozmowa odnośnie dostarczenia przedmiotu. Do pliku dodajemy:
<dialog id = "zadanie_z_kanistrem_complete"> <has_info>kanister_have</has_info> <dont_has_info>kanister_done</dont_has_info> <phrase_list> <phrase id = "0"> <text>esc_kanister_complete_0</text> <next>1</next> </phrase> <phrase id = "1"> <text>esc_kanister_complete_1</text> <give_info>kanister_done</give_info> <action>tutorial.gasoline_done</action> <next>2</next> </phrase> <phrase id = "2"> <text>esc_kanister_complete_2</text> <action>dialogs.break_dialog</action> </phrase> </phrase_list> </dialog>
Gdzie:
□ has_info - dialog pojawi się, gdy mamy informację “kanister_have” - czyli zgodnie ze skryptem, w którym zdefiniowaliśmy funkcję oraz wiążącymi wpisami z pkt. 8 poradnika.
[*]
Musimy również dodać do pliku character_desc_escape.xml - tak samo jak w pkt.3 poradnika /sekcja dialogów Wilka/.
<actor_dialog>zadanie_z_kanistrem_complete</actor_dialog>
[*]Uzupełniamy plik tutorial.script o ostatnią funkcję, która występuje w drzewie skryptowo-dialogowym - pkt 9 poradnika - przy esc_kanister_complete_1. (poniżej funkcji już dodanych w pliku).
--- dla infoportion_donefunction gasoline_done(first_speaker, second_speaker)dialogs.relocate_item_section(first_speaker, "explosive_mobiltank", "out")dialogs.relocate_item_section(second_speaker, "wpn_spas12", "in")end
Powyższa funkcja odpowiada za zakończenie zadania, oddanie przedmiotu i otrzymanie nagrody.
Rozważmy wpisy tworzące funkcję:
Poprzez dialog (dialogs) następuje przeniesienie przedmiotu (relocate_item_section) pomiędzy rozmówcami (first_speaker, second_speaker). Jeśli mamy wpis “out” - to oddajemy przedmiot, przy którym stoi wpis, natomiast “in” to przedmiot otrzymywany - w naszym przykładzie jest to Spas12.
[*]
Oraz uzupełniamy plik stable_dialogs_escape.xml [gamedataconfigtextpol] - jak w pkt.6
<string id="esc_kanister_complete_0"> <text>Znalazłem kanister!</text> </string> <string id="esc_kanister_complete_1"> <text>Dobra robota Naznaczony.</text> </string> <string id="esc_kanister_complete_2"> <text>Wisisz mi kolejkę stary.</text></string>
[*]
Do pliku storyline_info_escape.xml [gamedataconfiggameplay]
dodajemy (opis zgodnie z wierszem: opis_zadania_testowego - patrz pkt.8) wpis:
<article id="opis_zadania_testowego" name="new_task" article_type="task" group="new_task/0"> <text>opis_zadania1</text></article>
[*]Powyższy plik prowadzi do spolszczenia kwestii dialogowej tj. stable_storyline_info_escape.xml [gamedataconfigtextpol] w którym dodajemy wpis:
<string id="opis_zadania1"> <text>Muszę wywiązać się z ważnego dla Wilka - zadania dostarczenia benzyny do agregatu w wiosce, tylko tak mogę udowodnić swoją wartość jako nowicjusz.</text></string>
[*]W moim przykładzie wykorzystałem kanister, toteż w pliku weapons.ltx [gamedataconfigweapons] odnajdujemy nasz przedmiot z pliku tutorial.script czyli explosive_mobiltank i zmieniamy sekcję z:
can_take = false
na:
can_take = true
Zmiana wpisu umożliwi zabranie przedmiotu do ekwipunku, co przedtem nie było możliwe.
Pozostaje jeszcze kwestia drugorzędna - zrobienia ikony dla kanistra, jednak to już temat innego tutoriala. Screeny prezentujące nowe zadanie:
.thumb.jpg.43be02f0834ee5274da4fe18f0d6d93e.jpg).jpg.a1c42ea6058a9dcd32e8934f836d03c2.jpg)
Jeśli ktokolwiek będzie miał - przeczytawszy powyższe wskazówki - wątpliwości dotyczące tworzenia zadań - w załączeniu pliki w formie sfinalizowanej - instalacja poprzez skopiowanie gamedata.
Uwagi dla administracji**:** - dotyczące podobnego tematu.
Spoiler
Ponieważ podobny tutorial już został napisany, w
Tworzenie kwestu [Mod Wiki], pragnę nadmienić iż niniejsze opracowanie nie służy dublowaniu wątków. Merytoryczna część poradnika dotycząca szczegółów tworzenia własnych funkcji (skrypty) oraz zagadnień ukazujących sposób połączeń plików - dla ich poprawnego funkcjonowania - jak również przedstawiających sposób zbierania informacji o punktach terenowych - jest znacznie bardziej rozbudowana, niż ta podana w linku a odnosząca się do podobnego tematu. Chciałbym zwrócić uwagę na pewien fakt, otóż poradnik - nadmieniony w linku - nie jest kompletny, na jego podstawie nie da się zbudować nowego questu, ponieważ brakuje kilku istotnych tagów - wpisy ujęte w code. Warto sprawdzić to co mówię, porównując zawartość z artykułem, w oparciu o który - powstał.
Poradnik opracowany na podstawie plików Solijanki:
Prawa autorskie na podstawie regulaminu, pkt.1.6. - The Emperor, wyłączność: StalkerTeam.
_________________________
Autor: The Emperor dla StalkerTeam



