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 </supplies> , 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 <action>tutorial.spawn_kanister</action> - 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 </dialog> 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: <article>opis_zadania_testowego</article> - 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:
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.
new_quest_tutorial.7z (32.8 KB)
Uwagi dla administracji** :** - dotyczące podobnego tematu.
Spoiler
Ponieważ podobny tutorial już został napisany, w
, 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