Tworzenie przerywników filmowych

0. Wstęp
1. Podstawy
1.1 Przygotowanie
1.2 Początek przerywnika
1.3 Tworzenie przerywnika
Metoda I
Metoda II
1.4 Zakończenie przerywnika
1.5 Rozruch skryptu i modyfikacja
2. Elementy trudniejsze
2.1 Narracja
2.2 Gra aktorska
2.21 Mimika
2.22 Dźwięk
Metoda I
Metoda I+
Metoda II
2.221 stringtable.csv
2.222 *.Lip files
2.23 Muzyka
2.24 Animacje
2.241 Pierwsza grupa animacji
2.242 Druga grupa animacji
2.243 Trzecia grupa animacji
3. Elementy dodatkowe
3.10 Efektowne przejścia
3.11 Zmiany pory dnia
3.12 Zmiany warunków atmosferycznych
3.13 Przyspieszanie i spowalnianie upływu czasu
3.14 Nakładki
3.15 Przybliżanie i oddalanie widoku
3.16 Ustawianie kamery względem obiektu
3.17 Obracanie kamery wokół punktu
3.18 Kamera towarzysząca
3.19 Kamera towarzysząca wykonująca obrót

0. Wstęp

W OFP przerywniki filmowe (Cutscenes) można tworzyć na dwa sposoby: za pomocą wyzwalaczy i za pomocą zewnętrznych skryptów (External scripts) , czyli programów napisanych w języku skryptowym OFP, umieszczonych w plikach z rozszerzeniem .sqs (zwykle nazywane są "Camera.sqs" lub "Cutscene.sqs"). Osobiście jestem zwolennikiem tego drugiego rozwiązania, gdyż uważam, że dzięki takiej formie łatwiej jest kontrolować przebieg danej scenki. Sądzę, że opanowanie tej sztuki nie jest takie trudne jak mogłoby się z pozoru wydawać (nawet dla kogoś kto nie ma zielonego pojęcia o programowaniu).
Poradnik ten wymaga pewnej elementarnej wiedzy z zakresu edytora OFP. Przez powyższe należy rozumieć, że nie zamierzam tłumaczyć co to jest wyzwalacz (trigger), synchronizacja, jak umieścić jednostkę na mapie ect...
Ponadto nie jest to poradnik na temat tworzenia skryptów zewnętrznych jako takich , a jedynie na temat tworzenia za ich pomocą przerywników filmowych.
Poradnik ten jest całkowicie nieoficjalny i nie jest powiązany w jakikolwiek sposób z BIS ani Codemasters (eh...no może poza tym że to oni stworzyli i wydali OFP ;] ). Nie gwarantuję, że użycie informacji w nim zawartych da jakieś wymierne efekty i nie jestem w stanie zagwarantować, że ustrzegłem się pomyłek (byłbym wdzięczny za poinformowanie mnie jeśli odkryjesz jakąś pomyłkę). Ponadto zawarte w poradniku informacje wykorzystujesz na własną odpowiedzialność (co oznacza, że nie odpowiadam za format dysku twardego, pożar instalacji elektrycznej ect... ;).
Podczas powstawania tego poradnika nie ucierpiało żadne zwierzę, a jedno miało przy tym dużo przyjemności (...i to nie byłem ja).

1. Podstawy

1.1 Przygotowanie

Na dobry początek trzeba mieć wykonaną misję, w której chce się umieścić przerywnik filmowy (tj. mieć plik z rozszerzeniem sqm) i mieć plan (choćby w zarysie) tego jaki będzie przebieg przerywnika tj. co będzie się działo i w jakiej kolejności.
Kolejnym krokiem jest stworzenie pustego pliku .sqs. Do tworzenia skryptów używam programu "OFP Script Editor", którego autorem jest Peter Pearson "Manteau", ale równie dobrze można użyć notatnika (Notepad).
W tym celu należy powiązać rozszerzenie sqs z notatnikiem (jeżeli tego nie zrobimy notatnik będzie zapisywał wszystko jako txt). Uzyskujemy to wybierając "Otworzyć z..." (opcja w menu kontekstowym) i otwierając dowolny plik sqs notatnikiem (pliki sqs powinne mieć teraz symbol notatnika, ale możesz to zmienić...ja mam ikonkę OFP ;]). Gdy tak się stanie możemy tworzyć skrypty w notatniku i zapisywać je używając "Zapisz jako..." i wpisując w polu "Nazwa pliku" np.Cutscene1.sqs.

1.2 Początek przerywnika

Mamy więc pusty plik sqs. By powstał przerywnik filmowy konieczne jest umieszczenie w pliku paru poleceń (surprise!). Do podstawowych należą (podane w kolejności ich umieszczania):

TitleCut ["tekst", "BLACK IN", n] - polecenie to powoduje przejście ekranu z "czarnego" do "przezroczystego" w czasie n sekund, z jednoczesnym wyświetleniem dowolnego tekstu umieszczonego w cudzysłowie (można nic nie umieszczać, ale cudzysłów musi być).
Dzięki temu zabiegowi przerywnik zyskuje na profesjonalności. Można użyć również wariantu "WHITE IN" dającego przejście ekranu z "białego" do "przezroczystego", ale widzę dla niego inne zastosowanie (o tym później...).

EnableRadio false - polecenie to sprawi, że komunikaty radiowe nie będą się pojawiały w trakcie trwania przerywnika. Polecenie to można odwołać w dowolnym momencie (a nawet trzeba pod koniec przerywnika) umieszczając w skrypcie komendę EnableRadio true.

_cam = "CAMERA" CamCreate [0,0,0] - polecenie to tworzy w punkcie o współrzędnych [0,0,0] kamerę, powiązując ją ze zmienną lokalną _cam (przez tą zmienną będziemy odwoływać się do kamery wydając jej polecenia). Oczywiście można stworzyć kamerę w innym miejscu, ale nie ma to znaczenia bo i tak zaraz zmienimy jej położenie.

_cam CameraEffect ["INTERNAL","BACK"] - polecenie to uruchamia kamerę powiązaną ze zmienną _cam, jednocześnie określając jaka ma być i gdzie ma być położona względem filmowanego celu (ale tym się nie przejmujcie, gdyż przynajmniej mnie nie udało się tego z pożytkiem użyć. Wpiszcie tylko "INTERNAL","BACK").

1.3 Tworzenie przerywnika

Teraz to co najważniejsze, czyli treść przerywnika. Ogólnie rzecz biorąc przerywnik powstaje w ten sposób, że:
- kamera ma w swoim polu widzenia jakiś obiekt (poruszający się lub nieruchomy), przy czym obiektem tym może być także jakiś punkt w przestrzeni 3D,
- kamera zmienia swoją pozycję poruszając się z pewną prędkością między dwoma punktami w przestrzeni 3D.

Do tego pomijając różne "bajery" sprowadza się tworzenie przerywnika w OFP tj. do określenia:
- w co (bądź gdzie) wycelowana jest kamera,
- gdzie jest kamera i jeżeli się porusza, to dokąd i ile czasu jej to zajmie.

Do przekazywania kamerze powyższych informacji służą następujące polecenia:

_cam CamSetTarget nazwa_obiektu - polecenie to nakazuje kamerze "podążać wzrokiem" za obiektem o podanej nazwie tzn. że jeżeli celem będzie jadący samochód kamera bez naszej pomocy utrzyma go w polu widzenia (no chyba, że coś zasłoni jej widok, ale wtedy i tak będzie wycelowana w odpowiednim kierunku) nie zmieniając przy tym swojej pozycji. Oczywiście wydanie polecenia śledzenia innego celu odwołuje poprzednie polecenie.
Zamiast podania nazwy obiektu możemy podać współrzędne punktu na który ma być skierowana kamera tj. _cam CamSetTarget [_x,_y,_z] (kamera niestety nie będzie "podążać wzrokiem" za podanymi współrzędnymi). To wymaga trochę wyjaśnień (zwłaszcza dla tych którzy nie mają doświadczenia w tworzeniu skryptów). Oczywiście można by zamiast tych zmiennych wpisać liczby, ale raczej nie sposób zgadnąć jakie. Zamiast zgadywania polecam wpisywać następujący ciąg komend:

_ox = GetPos nazwa_obiektu Select 0
_oy = GetPos nazwa_obiektu Select 1
_oz = GetPos nazwa_obiektu Select 2
_cam CamSetTarget [_ox,_oy,_oz]

Pierwsze trzy linijki komend powodują przypisanie zmiennym lokalnym _ox,_oy,_oz współrzędnych obiektu o podanej nazwie np. jednostki, markera czy wyzwalacza.
Zamiast powyższego możemy wpisać _cam CamSetTarget GetPos nazwa_obiektu co daje taki sam efekt, ale uniemożliwia nam ewentualne ustawienie celu kamery względem obiektu za pomocą wpisania "wektora przesunięcia" np. _cam CamSetTarget [_ox+5,_oy,_oz+10].

_cam CamSetPos [_x,_y,_z] - polecenie to nakazuje kamerze zająć pozycję o współrzędnych określonych przez zmienne lokalne _x,_y,_z.
Podobnie jak w poprzedniej komendzie najlepiej użyć:

_ox = GetPos nazwa_obiektu Select 0
_oy = GetPos nazwa_obiektu Select 1
_oz = GetPos nazwa_obiektu Select 2
_cam CamSetPos [_ox,_oy,_oz]

Osobiście stosuję metodę polegającą na umieszczaniu wyzwalaczy o nazwach np. pozycjakamery1, pozycjakamery2, pozycjakamery3 itd... dzięki czemu umiejscawiam na mapie kolejne pozycje do których przemieszczać się będzie kamera (bądź w które będzie wycelowana za pomocą CamSetTarget).
Druga metoda umiejscawiania kamery względem celu wiąże się z kolejnym poleceniem...

_cam CamSetRelPos[i,j,k] - polecenie to nakazuje kamerze zająć pozycję o współrzędnych celu zwiększonych o wartości i,j,k. To oznacza, że kamera zajmie pozycję przesuniętą względem współrzędnych celu o wektor [i,j,k].
Mówiąc po ludzku jeżeli wpiszemy _cam CamSetRelPos[0,-5,3], to kamera znajdzie się 3 metry wyżej niż filmowany obiekt i 5 metrów od niego (czy za nim, to trudno powiedzieć, bo to zależy w którą stronę jest zwrócony). Polecenie to jest bardzo użyteczne, gdy nie mamy możliwości przewidzieć, gdzie dokładnie w trakcie trwania przerywnika znajdzie się filmowany obiekt, a zależy nam by kamera znalazła się w określonej odległości od niego.

_cam CamCommit n - bardzo ważne polecenie, o którego umieszczeniu nie można zapomnieć, gdyż w przeciwnym wypadku nic się nie zadziała. Zatwierdza ono wprowadzone wcześniej (za pomocą poleceń CamSetTarget, CamSetPos, CamSetRelPos) zmiany dotyczące kamery tj. jej położenia i celu. Wartość n określa w jakim czasie (w sekundach) ma być dokonana zmiana, co daje nam możliwość zarówno błyskawicznego "przeskoku" z jednego miejsca do drugiego jeżeli podamy n równe 0, jak i powolnego (bądź też szybkiego) przemieszczania kamery z jednego punktu do drugiego, gdy podamy określoną dodatnią wartość n. Po tym poleceniu musimy dać czas kamerze na wykonanie zmian wpisując @CamCommitted _cam co spowoduje zatrzymanie wykonania skryptu na czas podany w poleceniu CamCommit (polecenie @warunek powoduje zatrzymanie działania skryptu do momentu spełnienia warunku tj. przyjęcia wartości logicznej true).

Istnieje także polecenie _cam CamSetDir n, które powoduje obrócenie kamery w danym kierunku, gdzie n to wartość w stopniach (od 0 do 360), aczkolwiek raczej rzadko się z niego korzysta.

Mając tą wiedzę jesteśmy w stanie (prawie) zacząć tworzyć przerywnik. Brakuje nam jednak wiedzy na temat sposobu w jaki określić kiedy kamera ma zmieniać cele, położenie itd.
Metod jest kilka...

Metoda I

Po pierwsze możemy spowodować zatrzymanie działania skryptu na określony czas wpisując polecenie: ~n gdzie n to czas w sekundach, na który wykonywanie skryptu ma być zatrzymane.
Metoda ta jest o tyle kłopotliwa, że konieczne jest wielokrotne sprawdzanie, w którym momencie (tj. po upływie jakiego czasu) ma nastąpić np. zmiana położenia kamery.

Metoda II

Druga (nieco lepsza metoda) polega na użyciu zmiennych globalnych, nazw obiektów i przede wszystkim wyzwalaczy. Można by pisać o tym wiele, więc posłużę się przykładem, który (mam taką nadzieję) wyjaśni o co mi chodzi.
Jeżeli filmujemy jadący samochód i chcemy by wykonane zostały cztery ujęcia (tzn. umieściliśmy wzdłuż drogi cztery obiekty, które posłużą do "zakotwiczenia" kamer), to zamiast sprawdzać ile sekund zajmie mu pokonanie poszczególnych odcinków drogi (pomiędzy punktami w których znajdzie się kamera), możemy ustawić cztery wyzwalacze, które uaktywnią się, gdy samochód znajdzie się w ich obszarze. Jeżeli w polach "Przy Aktywacji" tych wyzwalaczy umieścimy przypisania: pozycja1 = true (w pierwszym wyzwalaczu), : pozycja2 = true (w drugim wyzwalaczu) itd... oraz w skrypcie w odpowiednich miejscach @pozycja1, @pozycja2 itd.. spowodujemy, skrypt będzie czekał, aż samochód dotrze do odpowiednich punktów na drodze (ile czasu mu to zajmie nie ma znaczenia).

Niezłym sposobem jest też użycie w skrypcie komendy: @(nazwa_obiektu1 Distance nazwa_obiektu2<odległość). Spowoduje to, że skrypt wstrzyma swoje działanie do chwili, aż obiekt1 znajdzie się w odległości mniejszej niż podana odległość w metrach od obiektu2 (można sprawdzić ile to będzie na mapie, stawiając wyzwalacz o określonym promieniu).

Oczywiście jako warunku można użyć każdego ciągu poleceń dającego w wyniku wartość logiczną (boolean) np. @((PLAYER In truck1) AND (NOT Alive sucker1)).

Podsumowując poważną wadą tego rozwiązania jest to, że jeśli z jakichś względów warunek nie zostanie spełniony (np. samochód ulegnie zniszczeniu między punktami), skrypt nie będzie mógł zakończyć swego działania.

1.4 Zakończenie przerywnika

Na koniec musimy jeszcze wpisać następujące linijki kodu:

TitleCut ["tekst", "BLACK OUT", n] - wpisanie tej linijki daje odwrotny efekt niż na początku przerywnika tj. przejście ekranu od "przezroczystego" do "czarnego" (dzięki zastąpieniu "BLACK IN" wyrażeniem "BLACK OUT"). Czas przejścia i wyświetlany tekst wprowadzamy tak jak poprzednio podając n (w sekundach) i wpisując dowolny tekst. Dodatkowo musimy wstawić opóźnienie w postaci ~n (o takiej samej wartości jak we wcześniejszym TitleCut).

_cam CameraEffect ["TERMINATE","BACK"] - polecenie to zakończy pracę kamery związanej ze zmienną lokalną _cam.

CamDestroy _cam - polecenie niszczy kamerę (!) związaną ze zmienną lokalną _cam (podejrzewam, że po prostu uwalnia procesor od obciążenia związanego z istnieniem kamery).

Jeżeli wcześniej tego nie zrobiliśmy to uruchamiamy radio za pomocą EnableRadio true.

Jeszcze raz wpisujemy TitleCut ["tekst", "BLACK IN", n], by po zakończeniu skryptu nie zostać z czarnym ekranem.

DisableUserInput false - by gracz mógł robić cokolwiek po zakończeniu skryptu.

...i kończymy działanie skryptu wpisując Exit.

1.5 Rozruch skryptu i modyfikacja

Kiedy skrypt jest już gotowy należy umieścić go w tym samym katalogu co plik mission.sqm oraz umieścić w misji komendę [] Exec "nazwa_skryptu.sqs". To gdzie powinno się umieścić tę komendę zależy od tego kiedy przerywnik ma się uruchomić. Jeżeli jest to intro, outro lub scenka rozpoczynająca misję to należy umieścić go w polu Inicjacja dowolnej jednostki odpowiednio na mapie Wstęp (Intro), Przegrana (Outro) lub mapie misji. Jeżeli natomiast przerywnik ma wystąpić w trakcie misji (np. po zakończeniu jakiegoś jej etapu) to wpis ten powinien znaleźć się w polu "Przy aktywacji" odpowiednio określonego wyzwalacza.

Uwaga! Warto dobrze zastanowić się nad momentem uruchomienia przerywnika w trakcie misji (tj. tak naprawdę warunkiem aktywacji wyzwalacza), gdyż uruchomienie skryptu odbierze graczowi możliwość działania i obserwowania tego co się wokół niego dzieje, jednocześnie nie ograniczając możliwości działania jego przeciwników. Wniosek z tego jest taki, że najlepszym momentem na przerywniki w trakcie misji są chwile względnego spokoju, takie jak np. podróże jakimś środkiem transportu (misja zyskuje wiele, gdy nudną i długą podróż zastępuje się przerywnikiem).

Gdy zrobimy powyższe pozostaje tylko uruchomić podgląd i obejrzeć efekt. Pewien kłopot powstaje, gdy misja jest długa, a przerywnik jest gdzieś w połowie (lub nawet na końcu). Rozwiązaniem tego problemu jest wykonanie zapisu stanu gry tuż przed uruchomieniem skryptu i (jeżeli coś nie gra) wczytanie stanu gry tuż po jego zakończeniu (jeżeli zmodyfikowaliśmy skrypt to przerywnik będzie zawierał naniesione poprawki tzn. nie ma potrzeby zaczynania misji od początku). Drugim sposobem jest wykonanie filmiku jako osobnej misji i scalenie jej z misją właściwą (niestety czasem jest to dosyć kłopotliwe, toteż nie polecam).

2. Elementy trudniejsze

Jak już pisałem wcześniej przerywnik filmowy tworzą: kamera, obiekt filmowany, ich wzajemna zmiana położenia względem siebie i czas tej zmiany. Oczywiście są to jedynie podstawowe elementy (gdyby przerywnik składał się tylko z tego byłby śmiertelnie nudny)i istnieje sporo innych czyniących przerywnik bardziej atrakcyjnym wizualnie. Do dodatkowych elementów zaliczył bym narrację (subtitles), grę aktorów (dialogi i ruch sceniczny) oraz tło (odgłosy, muzyka, pogoda). Wszystkie te elementy możemy zawrzeć w naszym przerywniku umieszczając w skrypcie odpowiednie komendy.

2.1 Narracja

Do umieszczania na ekranie napisów służy (oprócz wspomnianej wcześniej komendy TitleCut) komenda TitleCut["tekst_wyświetlany","PLAIN DOWN",n] która wyświetli dany tekst u dołu ekranu w czasie n sekund (można pominąć ten parametr-wtedy domyślnie przyjmowane jest n=1). Zamiast "PLAIN DOWN" możemy użyć "PLAIN" wtedy napis znajdzie się na środku ekranu.

2.2 Gra aktorska

Do tej pory nasza kontrola nad przebiegiem przerywnika (z poziomu skryptu) ograniczała się do kontroli nad kamerą. Tak jednak być nie musi. Możemy wpływać na zachowanie obiektów filmowanych na tyle na ile pozwala na to język skryptowy OFP (czyli właściwie sprawujemy nad nimi kontrolę w takim samym stopniu jak tworząc misję w edytorze). Przez powyższe stwierdzenie należy rozumieć , że możemy w skrypcie umieścić każdą komendę wpływającą na istniejący obiekt (np. Jednostkę) której użylibyśmy np. w jej polu Inicjacja (Init Field), w polu "Przy aktywacji" wyzwalacza lub w polu "Przy aktywacji" punktu trasy (WayPoint). Wniosek z tego taki, że wszystkie polecenia typu : SetBehaviour, OrderGetIn, AssignAsCargo, DoMove, CommandFire ect.. ect... (pozwolę sobie nie przepisywać całego CMREFu) umieszczone w skrypcie, zadziałają w zadanym momencie.

Jeżeli obiektem filmowanym jest człowiek mamy znacznie większe możliwości w zakresie gry aktorskiej, niż ma to miejsce w przypadku statycznego obiektu, czy nawet pojazdu (heh...świetny tekst...mam dziś wenę twórczą ;] ). Wynika to oczywiście z faktu, że ludzie mogą mieć coś do powiedzenia oraz z istnienia komend SetMimic zmieniającej mimikę twarzy osoby i PlayMove pozwalającej skorzystać z całej gamy animacji dostępnych w OFP.

2.21 Mimika

Aby zmieniła się mimika twarzy aktora należy w odpowiednim miejscu skryptu wpisać polecenie nazwa_aktora SetMimic "mimic" . Możliwe wartości parametru mimic to: "Default", "Normal", "Smile", "Hurt", "Ironic", "Sad", "Cynic", "Suprised", "Agresive" (literówka!), "Angry". Powrót do normalnego (obojętnego) wyrazu twarzy uzyskujemy parametrem "Default" lub "Normal" (jest jakaś różnica? Ja nie zauważyłem).

2.22 Dźwięk

Dialogi stanowią bardzo rozbudowane zagadnienie. Najprostsza metoda polega na użyciu omawianej wcześniej komendy TitleText czyli na wyświetleniu wyświetlenie napisu tłumaczącego/informującego co zostało powiedziane. Niestety nie mamy w tej sytuacji ani dźwięku ani ruchu warg co zmusza do unikania zbliżeń twarzy.Tak samo wygląda kwestia użycia komend radiowych tj. GlobalChat, SideChat, GroupChat, VehicleChat (należy pamiętać, by wcześniej odwołać blokowanie komunikatów radiowych ustawione za pomocą EnableRadio false).

By uzyskać dźwięk lub chociaż ruch warg mówiącej osoby, musimy uciec się do bardziej skomplikowanych metod:

Metoda I

Pierwsza (prostsza) metoda polega na użyciu istniejących w grze plików dźwiękowych (czyli niestety jesteśmy tym samym ograniczeni do około czterdziestu krótkich kwestii w dwóch językach). W tym celu wystarczy umieścić w odpowiednim miejscu skryptu polecenie nazwa_aktora Say "ID_kwestii".

Istnieją następujące kwestie (jeżeli tekst się powtarza to oznacza, że jest wypowiadany przez różne osoby, co pozwala uniknąć wrażenia że wszyscy mówią jednym głosem):

ENG1 Bastards!
ENG2 Bastards!
ENG3 Bastards!
ENG4 Commie!
ENG5 Commie!
ENG6 Cover me!
ENG7 Cover me!
ENG8 Die!
ENG9 Die!
ENG10 Die!
ENG11 Don't shoot we're unarmed!
ENG12 Enemy spotted, open fire!
ENG13 Everyone out!
ENG14 Everyone out!
ENG15 Forward!
ENG16 Get out of here!
ENG17 Get out of here!
ENG18 Get to your positions!
ENG19 Get to your positions!
ENG20 Go, go, go!
ENG21 Go, go, go!
ENG22 Help!
ENG23 Help!
ENG24 Hey, what are you doing there?
ENG25 Hey, what are you doing there?
ENG26 Hey, what are you doing there?
ENG27 Let them have it!
ENG28 Let them have it!
ENG29 Look out!
ENG30 Look out!
ENG31 Look out!
ENG32 Medic, I am hit!
ENG33 Medic, I am hit!
ENG34 Medic, I am hit!
ENG35 Sector clear, take it easy
ENG36 Sector clear, take it easy
ENG37 Stay sharp, they're all around us
ENG38 We surrender!
ENG39 We're under attack. Return fire!
ENG40 Who's there?
ENG41 Who's there?
RUS1 American devils
RUS2 Run away, all, run away!
RUS3 Devil's dogs
RUS4 Damn
RUS5 Damn
RUS6 Hey you. What are you doing there?
RUS7 I surrender!
RUS8 Mamo...
RUS9 Don't shoot. We're unarmed
RUS10 Fire!
RUS11 Cease fire
RUS12 Get out!
RUS13 Help!
RUS14 Freeze!
RUS15 Alarm
RUS16 Vodka!
RUS17 Vodka?
RUS18 Forward
RUS19 Sector clear
RUS20 Die, bastard

Kwestie rosyjskojęzyczne (RUS1-20) są oczywiście wypowiadane po rosyjsku.

Jak widać nie mamy do wyboru zbyt zróżnicowanych zwrotów i nie za bardzo da się z tego sklecić jakąś sensowną rozmowę.

Metoda I+

Można ewentualnie spróbować nieco pokombinować umieszczając np. następujące linijki kodu:

0 FadeSound 0
nazwa_aktora Say "RUS6"
TitleText["Ruszać się panienki! Nie płacą nam od godziny","PLAIN DOWN"]
~2.5
0 FadeSound 1

Wpisując powyższe otrzymujemy co prawda bezdźwięczny dialog (w tym przypadku właściwie monolog ;), ale za to już z ruchem warg (niestety niezgodnym z wypowiadaną kwestią... no cóż w latach 80-tych dubbing nie był jeszcze na najwyższym poziomie ;).

Metoda II

Metoda trudniejsza polega na stworzeniu własnych plików dźwiękowych o rozszerzeniu .ogg oraz związanych z nimi plików (kontrolujących ruch warg przy wypowiedzi) o rozszerzeniu .lip. Jakby tego nie było dość, musimy jeszcze stworzyć, na potrzeby obsługi dźwięku w misji, pliki description.ext i stringtable.csv.

Do wykonania powyższego zadania potrzebne są programy Ogg Drop oraz Wav2Lip oraz pliki z rozszerzeniem .wav (które zawierają kwestie do umieszczenia w misji).

Uwaga! Pliki te muszą dodatkowo spełniać pewne warunki tj. muszą mieć 16 bit, 44100 kilohertz, 64 kbps bit rate. Ponadto muszą być Mono (dotyczy to mowy i dźwięków, tło muzyczne może być Stereo). Musicie skorzystać z jakiegoś programu do obróbki dźwięku by zmienić ich format jeżeli jest inny niż podany.

Kolejnym krokiem jest użycie Ogg Drop'a. W tym celu uruchamiamy go i klikamy na okienko z rybką (takowe powinno się pojawić) prawym klawiszem myszy otwierając menu kontekstowe. Następnie rozwijamy opcję Bitrate i wybieramy 64 kbps (niestety domyślny dla Oggdrop'a bit rate to 80,więc trzeba za każdym razem pamiętać o dokonaniu tej zmiany). Na koniec przeciągamy plik .wav na okienko z rybką (będziecie wiedzieli gdzie to jest, zresztą napisane jest tam "Drop files here"). W efekcie w katalogu w którym jest Oggdrop pojawi się plik o nazwie takiej jak .wav tyle, że z rozszerzeniem .ogg. Plik ten umieszczamy w specjalnym folderze o nazwie Sound, który tworzymy w folderze naszej misji (czyli np. C:\ Program Files\ Codemasters\ OperationFlashpoint\ Users\ Alderous\ missions\ Moja_misja\ Sound).

Teraz konieczne jest stworzenie pliku description.ext, który znajdzie się w folderze z naszą misją (plik description.ext może służyć do wielu innych rzeczy, ale nie będę ich omawiał przy tej okazji). By stworzyć taki plik wystarczy notatnik (Notepad is your best friend ;). Dla opisania plików z dialogami i dźwiękami wpisujemy: (na czerwono zaznaczyłem fragment, który dotyczy jednego pliku .ogg):

class CfgSounds
{
sounds[] = {nazwa_klasy1,nazwa_klasy2};

class nazwa_klasy1
{
name = "";
sound[] = {"nazwa_pliku1.ogg", db-40, 1.0};
titles[] =
{
0, $STRM_ komentarz1
};
};

class nazwa_klasy2
{
name = "";
sound[] = {"nazwa_pliku2.ogg", db-40, 1.0};
titles[] =
{
0, $STRM_ komentarz21
3, $STRM_ komentarz22
};
};
};

Jak widać każdy { musi być zakończony }; . Musimy opisać każdy plik tj. powtórzyć zielono zaznaczony fragment dla każdego pliku dźwiękowego, który chcemy umieścić w misji. Opisywanie polega na powiązaniu klas z nazwami plików (zwykle są takie same np. class gadka1 i plik gadka1.ogg) oraz na dodaniu komentarzy (tj. titles - aczkolwiek nie jest to konieczne, można nic nie wpisać między klamry), które pojawiają się automatycznie (nie trzeba używać TitleText). Warto zauważyć, że w przypadku dźwięków możliwe jest dodanie kilku komentarzy do jednego pliku (w przypadku komunikatów radiowych nie jest to możliwe). Kolejne komunikaty będą się pojawiały po upływie czasu podanego przy nich (w powyższym przykładzie: pierwszy wyświetli się od razu, a drugi w 3 sekundzie po rozpoczęciu emisji dźwięku). Jest to przydatne przy długich kwestiach, bo tekst może być wyświetlony tylko w jednej linijce. Parametr db-40 oznacza głośność odgrywania dźwięku, względem ustawionej w grze (można np wpisać db+30). Z kolei 1.0 to względna barwa dźwięku (relative pitch - popróbujcie pozmieniać ustawienia w Gracz->Edycja->Barwa głosu, to zrozumiecie co to jest).
Zamiast dialogu oczywiście możemy umieścić dowolny dźwięk i odtworzyć go podczas misji komendą PlaySound "nazwa_pliku".

Jeżeli dźwięki te mają być komunikatami radiowymi tj. wygenerowanymi za pomocą komend GlobalRadio, SideRadio, GroupRadio, VehicleRadio (wtedy dodawany jest na końcu charakterystyczny odgłos "radiowy") musi umieścić dla nich następny, bardzo podobny (niemal identyczny) fragment kodu. Różni się on tylko tym, że nazwa całej klasy to class CfgRadio (zamiast class CfgSounds) oraz tym, że przy opisie każdego pliku dźwiękowego piszemy:
title = $STR_RAD_ komentarz3 zamiast jak poprzednio:

titles[] =
{
0, $STRM_ komentarz3
};

Czyli nie ma możliwości umieszczenia więcej niż jednego komentarza.

2.221 stringtable.csv

Ostatnia sprawa to stworzenie pliku stringtable.csv. Plikt ten zawiera teksty potrzebne do użycia w grze (nie tylko do komentowania wypowiadanych kwestii). Dzięki jego użyciu możemy stworzyć misję, w której napisy będą wyświetlane w różnych językach, w zależności od wersji językowej gry. Ze względu na irytujący zwyczaj modyfikowania typów plików przez Exel'a proponuję stworzyć ten plik w notatniku (najlepiej było, by zmienić przypisanie rozszerzenia .csv z Exel'owskiego na Notepad'a). Piszemy więc w notatniku na przykład coś takiego (nawiązując do poprzednich przykładów):

LANGUAGE,English,Polish,Comment
STRM_komentarz1, "Sgt. Smith: Do you get me, soldier?!","Sierżant Kowalski: Dotarło do was żołnierzu?!",alpha
STRM_komentarz21, "Private Miller: "But, Sir. I'm afraid of shooting and I'm a pacifist by nature ","Szer. Młynarski: "Ależ obywatelu sierżancie, ja się boję wystrzałów i z natury jestem pacyfistą",aP
STRM_komentarz22, "Private Miller: "Do I have to shoot? Will it be enough if I carry a gun and look dangerously?","Szer. Młynarski: "Czy koniecznie muszę strzelać? Nie wystarczy jeśli będę trzymał w ręku karabin i wyglądał groźnie?",aP
STR_RAD_komentarz3, "This is Charlie One. We've got visual contact with enemy, over","Tu oddział Charlie. Nawiązaliśmy kontakt wzrokowy z wrogiem, odbiór",grupa Charlie

Tylko STR jest konieczne ciąg dalszy identyfikatora może być różny np. STR_kom2 ,STRCAMP_sound23).

Tak spreparowany plik wstawiamy do folderu z tworzoną misją. W komendach Say, GlobalRadio, SideRadio, GroupRadio, VehicleRadio używamy nazwy pliku.

Uwaga! Umieszczając powyższe komendy w skrypcie musimy pamiętać, że skrypt nie zaczeka na dokończenie wypowiedzi więc należy umieścić pewne opóźnienie o długości równej długości wypowiadanej kwestii (za pomocą ~n).

Z odtwarzaniem dźwięków wiąże się komenda t FadeSound v która powoduje ściszenie lub pogłośnienie dźwięków odtwarzanych w grze (ale nie muzyki). Parametr t określa w jakim czasie (w sekundach) ma nastąpić zmiana głośności, a z kolei parametr v określa o ile dźwięk ma być ściszony (gdy v<1, dla v=0 nie ma dźwięku), lub pogłośniony (v>1).

2.222 *.Lip files

Teraz kolej na stworzenie plików .lip które odpowiadają za ruch warg osób podczas wypowiedzi. Jak już wspominałem do tego potrzebny jest program Wav2Lip. Uruchamiamy program Wav2Lip i przeciągamy plik .wav (mam nadzieję że go nie skasowaliście po uzyskaniu ogg'a).W folderze w którym mamy plik wav pojawi się plik .lip o tej samej nazwie, który powinniśmy umieścić w tym samym katalogu co plik ogg.

Uwaga! Pamiętajcie, że plik musi być w formacie 16 bit, 44100 kilohertz, 64 kbps bit rate, Mono żeby Wav2Lip zadziałał.

Uwaga! Bardzo istotna. Zawartość description.ext ładuje się po wczytaniu misji (w edytorze) więc jeśli dokonamy jakichś zmian musimy wczytać misję jeszcze raz.

2.23 Muzyka

Dołączanie własnej muzyki do misji wymaga działań podobnych jak w przypadku dołączania dźwięków i dialogów. Podobnie jak poprzednio muzyka musi być zawarta w pliku .wav i spełniającym określone warunki tj. 16 bit, 44100 kilohertz, 64 kbps bit rate, tyle że tym razem może być również Stereo. Używając Oggdrop'a uzyskujemy muzykę w formacie .ogg (pamiętajcie o zamianie ustawień Ogg Drop'a na 64 kbps), którą tym razem kopiujemy do folderu Music który tworzymy w folderze misji, w której ma być użyta muzyka.
Podobnie jak poprzednio informację o muzyce musimy zawrzeć w description.ext. Tym razem definiujemy następująco:

class CfgMusic
{
tracks[]={nazwa_pliku1, nazwa_pliku2};

class nazwa_pliku1
{
name = "nazwa_pliku1";
sound[] = {\Music\ nazwa_pliku1.ogg, db+30, 1.0};
};
class nazwa_pliku2
{
name = "nazwa_pliku2";
sound[] = {\Music\ nazwa_pliku2.ogg, db+30, 1.0};
};
};

Oczywiście można tak jak poprzednio dodać tyle ścieżek dźwiękowych na ile ma się ochotę deklarując dla każdej z nich klasę (class nazwa_plikun).
To wszystko co jest należy zrobić. Odtwarzanie muzyki uruchamiamy komendą PlayMusic "nazwa_pliku". Podobnie jak w przypadku dźwięków istnieje komenda t FadeMusic v działająca na takich samych zasadach. Oczywiście użycie FadeMusic w celu stopniowego ściszenia muzyki na końcu przerywnika (zwykle przerywnik nie trwa tyle samo co tło muzyczne), jest jak najbardziej wskazane (o ile nie konieczne).

2.24 Animacje

Nim zacznę wyjaśniać jak używać animacji muszę zaznaczyć, że była to najdłużej opracowywana część tego poradnika. Jestem pewien, że wymaga uzupełnienia i poprawek, co mam zamiar zrealizować w kolejnych wersjach tego poradnika.

Do tej pory nie spotkałem się z opracowaniem zawierającym opis wszystkich animacji (ok. 400 choć przekonałem się , że jest ich jeszcze więcej), wymienionych w CMREF'ie (zwykle omówione jest ok. 20), toteż musiałem większość sprawdzić sam (na co nie miałem niestety zbyt dużo czasu).

Na dobry początek należy sobie uświadomić, że większość z 400 animacji każdy grający w OFP widział na własne oczy, chociaż może nie uświadamiał sobie tego. Animacje te po prostu są uruchamiane przez "engine" gry w odpowiedzi na nasze działania np. animacja "CombatRunF" jest używana zawsze, gdy jakiś żołnierz biegnie do przodu, z bronią w ręku (ponieważ odpowiada za przebiegnięcie ok.2m jest zapętlana). Oczywiście możemy je jednak wywołać na rządanie używając komend: nazwa_jednostki SwitchMove "nazwa_animacji" lub nazwa_jednostki PlayMove "nazwa_animacji" (w pierwszym przypadku zazwyczaj następuje natychmiastowe przejście do zadanej pozy). Jest to trochę rozczarowujące, gdyż okazuje się, że używanie jedynie 30-40 animacji ma jakiś sens, resztę można wywołać po prostu dając jednostkom rozkazy (np. po co używać, wymienionej już, animacji "CombatRunF" skoro można po prostu ustawić jednostce punkt trasy i zrobi dokładnie to samo). Wśród tych animacji znajduję się także animacje zawierające w nazwie Dead lub Dying, te oczywiście trwają aż do odwołania, ale nie oznacza to że, użycie ich wobec jednostki powoduje ich śmierć. Jest to o tyle istotne, że nie zadziałają wyzwalacze reagujące na nieobecność jednostek określonej strony. Wśród Animacji są takie, które kończą swe działanie same oraz takie, które trwają tak długo, aż nie nakażemy postaci wykonanie następnej animacji.

Uwaga! Ciekawe, że jeżeli jakąś animację umieścimy tak, by uruchomiła się z chwilą rozpoczęcia misji, to nawet jeśli "normalnie" trwa bez końca (tj. nawet uruchamianie kolejnych animacji nie sprawi, że AI "odzyska wolną wolę") to w tym przypadku możemy ją odwołać (badam dokładnie tę sprawę).

Ogólnie rzecz biorąc wszystkie animacje możemy podzielić na trzy grupy.

2.241 Pierwsza grupa animacji

Pierwszą z nich stanowią animacje odpowiadające za pozy i ruch jakie charakteryzują załogi .(Commander, Driver, Gunner) i pasażerów (Cargo, CoDriver) pojazdów. Nazwy tych animacji zaczynają się nazwą pojazdu, po czym następuje określenie, którego członka załogi dotyczy animacja i na końcu co animacja powoduje (np. "BMPCommanderOutDying" to animacja dowódcy BMP, odtwarzająca jego śmierć, w chwili gdy jest wychylony z włazu). Animacje te możemy wywołać jedynie za pomocą SwitchMove i trwają do odwołania (no chyba, że ktoś zastrzeli tych biedaków). Użycie ich wobec zwykłych piechurów powoduje dosyć zabawne, ale całkowicie nieprzydatne efekty (w stylu facet siedzący w powietrzu, albo zanurzony po pas w ziemi).
Ponieważ ich nazwy same się tłumaczą i ze względu na małą przydatność, podam je bez opisu:

"5TCoDriverV1", "5TCoDriverDead", "5TCoDriverDying", "5TDriver", "5TDriverV1", "5TDriverDead", "5TDriverDying", "AH1Pilot", "AH1PilotV1", "AH1PilotDead", "AH1PilotDying", "AH1Gunner", "AH1GunnerV1", "AH1GunnerDead", "AH1GunnerDying", "AH1Pilot", "AH1PilotV1", "AH1PilotDead", "AH1PilotDying", "BMPCommander", "BMPCommanderV1", "BMPCommanderOut", "BMPCommanderOutV1", "BMPCommanderOutDead", "BMPCommanderOutDying", "BMPDriver", "BMPDriverV1", "BMPDriverOut", "BMPDriverOutV1", "BMPDriverOutDying", "BMPGunner", "BMPGunnerV1", "BMPGunnerOut", "BMPGunnerOutV1", "BMPGunnerOutDying", "BMPGunnerOutDead", "CesnaCargo", "CesnaCargoV1", "CesnaCargoDead", "CesnaCargoDying", "CesnaPilot", "CesnaPilotV1", "CesnaPilotDead", "CesnaPilotDying", "HRLGunner", "HRLGunnerV1", "HRLGunnerDead", "HRLGunnerDying, "JeepCoDriver", "JeepCoDriverV1", "JeepCoDriverDead", "JeepCoDriverDying", "JeepCoDriverBack", "JeepCoDriverBackV1", "JeepCoDriverBackDead", "JeepCoDriverBackDying", "JeepGunner", "JeepGunnerV1", "JeepGunnerDead", "JeepGunnerDying", "JeepDriver", "JeepDriverV1", "JeepDriverDead", "JeepDriverDying", "M113Driver", "M113DriverV1", "M113DriverOut", "M113DriverOutV1", "M113DriverOutDead", "M113DriverOutDying", "M113Gunner", "M113GunnerV1", "M113GunnerDead", "M113GunnerDying", "M113Medic", "M113MedicV1", "M1A1Commander", "M1A1CommanderV1", "M1A1CommanderOut", "M1A1CommanderOutV1", "M1A1CommanderOutDead", "M1A1CommanderOutDying", "M1A1Gunner", "M1A1GunnerV1", "M1A1DriverOut", "M1A1DriverOutV1", "M1A1DriverOutDead", "M1A1DriverOutDying", "M2Gunner", "M2GunnerV1", "M2GunnerDead", "M2GunnerDying", "M60Commander", "M60CommanderV1", "M60CommanderOut", "M60CommanderOutV1", "M60CommanderOutDead", "M60CommanderOutDying", "M60Driver", "M60DriverV1", "M60DriverOut", "M60DriverOutV1", "M60DriverOutDying", "M60DriverOutDead", "M60Gunner", "M60GunnerV1", "Mi17Pilot", "Mi17PilotV1", "Mi17PilotDead", "Mi17PilotDying", "Mi24Gunner", "Mi24GunnerV1", "Mi24GunnerDying", "Mi24PilotV1", "Mi24PilotDead", "Mi24PilotDying", "Para", "ParaV1", "ParaDead", "ParaDying", "PBRDriver", "PBRDriverV1", "PBRDriverDead", "PBRDriverDying", "PBRGunner", "PBRGunnerV1", "PBRGunnerDead", "PBRGunnerDying", "ScudCoDriver", "ScudCoDriverV1", "ScudCoDriverDead", "ScudCoDriverDying", "ScudDriver", "ScudDriverV1", "ScudDriverDead", "ScudDriverDying", "SkodaCoDriver", "SkodaCoDriverV1", "SkodaCoDriverDead", "SkodaCoDriverDying", "SkodaCoDriverBack", "SkodaCoDriverBackV1", "SkodaCoDriverBackDead", "SkodaCoDriverBackDying", "SkodaDriver", "SkodaDriverV1", "SkodaDriverDead", "SkodaDriverDying", "T55Commander", "T55CommanderV1", "T55CommanderOut", "T55CommanderOutV1", "T55CommanderOutDead", "T55CommanderOutDying", "T55DriverOut", "T55DriverOutV1", "T55DriverOutDead", "T55DriverOutDying", "T55Gunner", "T55GunnerV1", "T72Commander", "T72CommanderV1", "T72CommanderOut", "T72CommanderOutV1", "T72CommanderOutDead", "T72CommanderOutDying", "T72DriverOut", "T72DriverOutV1", "T72DriverOutDead", "T72DriverOutDying", "T72Gunner", "T72GunnerV1", "T72GunnerOut", "T72GunnerOutV1", "T72GunnerOutDead", "T72GunnerOutDying", "T80CommanderOut", "T80CommanderOutV1", "T80CommanderOutDead", "T80CommanderOutDying", "T80GunnerOutV1", "T80GunnerOutDead", "T80GunnerOutDying", "TractorDriver", "TractorDriverV1", "TractorDriverDead", "TractorDriverDying", "UazCoDriver", "UazCoDriverV1", "UazCoDriverDead", "UazCoDriverDying", "UazDriver", "UazDriverV1", "UazDriverDead", "UazDriverDying", "UH60Gunner", "UH60GunnerV1", "UH60GunnerDead", "UH60GunnerDying", "UH60Pilot", "UH60PilotV1", "UH60PilotDead", "UH60PilotDying", "UralCoDriver", "UralCoDriverV1", "UralCoDriverDead", "UralCoDriverDying", "UralDriver", "UralDriverV1", "UralDriverDead", "UralDriverDying", "V3SCoDriver", "V3SCoDriverV1", "V3SCoDriverDead", "V3SCoDriverDying", "V3SDriver", "V3SDriverV1", "V3SDriverDead", "V3SDriverDying", "ZSUCommander", "ZSUCommanderV1", "ZSUCommanderOut", "ZSUCommanderOutV1", "ZSUCommanderOutDead", "ZSUCommanderOutDying", "ZSUDriver", "ZSUDriverV1", "ZSUDriverDead", "ZSUDriverDying", "ZSUGunner", "ZSUGunnerV1", "ZSUGunnerOut", "ZSUGunnerOutV1", "ZSUGunnerOutDead", "ZSUGunnerOutDying".

2.242 Druga grupa animacji

Drugą grupę animacji stanowią animacje używane podczas ruchu żołnierzy i cywilów oraz przy wykonywaniu pewnych specjalnych akcji (np. leczenie, podkładanie ładunku itd). Ich nazwy nie podlegają jakiejś uniwersalnej regule, ale zwykle zawierają określenie stanu w jakim znajduje się jednostka (tj. stanu w jakim używana jest domyślnie ta animacja np. Combat, Crouch, Stand ect...) i określenie czynności. Animacje te zwykle trwają tylko chwilę (normalnie w grze są zapętlone lub w jakiś sposób zatrzymywane), przy czym użycie PlayMove powoduje odtworzenie całej animacji, a SwitchMove tylko opisanego fragmentu (niektóre czynności wymagają animacji rozpoczynającej i kończącej) np. użycie: nazwa _jednostki PlayMove "CrouchToCombat" spowoduje, że żołnierz najpierw uklęknie po czym wstanie, podczas gdy użycie nazwa _jednostki SwitchMove "CrouchToCombat" sprawi, że nagle znajdzie się w pozycji klęczącej, po czym wstanie. Ich przydatność nie jest zbyt duża z racji tego, że w większości przypadków można je zastąpić po prostu używając komend powodujących wykonanie czynności opisywanych przez te animacje (odnosi się to zwłaszcza do animacji ruchu). Oto spis animacji:

"BinocCrouchToCrouch", "BinocLyingToLying", "BinocStandToStand", "BinocToCombat" - różne (w zależności od stanu jednostki) animacje zakończenia używania lornetki (przy PlayMove cała sekwencja podniesienia do oczu i opuszczenia), trwają tylko chwilę.

"Cargo", "CargoVer1", "CargoVer2", "CargoVer3", "CargoVer4", "CargoVer5" - różne wersje animacji postaci siedzących jako pasażerowie (zwykle widzicie to w ciężarówce), niektóre poruszają się. Animacje te wywołuje tylko komenda SwitchMove, trwają bez końca. Mogą być przydatne, bo żołnierzy można posadzić gdziekolwiek (nie muszą być w pojeździe).
"CargoDying", "CargoDead" - jak łatwo się domyśleć animacje umierania i martwego pasażera.

"Commander", "Driver", "Gunner", "Pilot" - wbrew nazwie animacje te zachowują się tak jak animacja "Cargo".

"CivilDead", "CivilDeadVer2", "CivilDying", "CivilDyingVer2" - dwie animacje martwych i umierających cywili, trwją oczywiście bez końca.
"CivilLying", "CivilLyingNoAim", "CivilLyingDying" - dwie wersje animacji leżących cywili i animacja umierającego leżącego cywila. Trwaja tylko chwilę.
"CivilLyingCrawlF", "CivilLyingCrawlL", "CivilLyingCrawlR" - animacja cywila czołgającego się do przodu (F) na prawo (R) i na lewo (L), trwa krótko.
"CivilWalkF", "CivilRunF" - animacja cywila idącego i biegnącego do przodu, trwa tylko chwilę.

Uwaga! Animacje dotyczące cywili można stosować również do żołnierzy (i na odwrót).

"CombatDead", "CombatDeadVer2", "CombatDeadVer3", "CombatDying", "CombatDyingVer2", "CombatDyingVer3", "CombatRelaxedDeadVer2", "CombatRelaxedDying", "CombatRelaxedDyingVer2" - różne animacje martwego i umierającego żołnierza, trwają bez końca.
"Combat", "CombatOptics", "CombatOpticsF", "CombatRelaxedStill" - działa tylko ze SwitchMove, żołnierz na chwilę przystawia broń do oka (?).
"CombatRelaxedStill" - ?
"CombatReloadMortarEnd" - animacja zakończenia ładowania granatu nasadkowego (Mortar) w przypadku użycia SwitchMove, lub cała sekwencja ładowania w przypadku użycia PlayMove.
"CombatRunF", "CombatRunLF", "CombatRunRF" - animacje biegu do przodu (F) po skosie na prawo (RF) i po skosie na lewo (LF).
"CombatRunB", "CombatRunLB", "CombatRunRB" - j.w. tyle że do tyłu (B).
"CombatRunL" , "CombatRunR" - animacje biegu w lewo (L) i prawo (R).
"CombatSprintF", "CombatSprintLF", "CombatSprintRF" - animacje szybkiego biegu do przodu (F) po skosie na prawo (RF) i po skosie na lewo (LF).
"CombatTurnL", "CombatTurnR" - nie powodują obrotu (choć "na logikę" powinne), żołnierz tylko przez chwilę się wierci (?).
"CombatRunDeadVer2", "CombatRunDying", "CombatRunDyingver2" - animacje śmierci i umierania podczas biegu, trwają bez końca.
"CombatRunBDead", "CombatRunBDeadVer2", "CombatRunBDying", "CombatRunBDyingver2" - animacje śmierci i umierania podczas biegu do tyłu, trwają bez końca.
"CombatRunFToLying" - animacja żołnierza padającego z biegu, niestety zaraz potem wstaje.
"CombatRunNF" - bardzo zabawna animacja. Działa tylko ze SwitchMove. Żołnierza nie da się zabić, bez przerwy biegnie przed siebie, przenikając przez ściany (?!).
"CombatThrowGrenadeEnd" - animacja kończąca rzut granatem, w przypadku użycia PlayMove następuje cała sekwencja rzutu.
"CombatRunThrowGrenadeEnd" - j.w. tyle że z biegu (większy zamach).
"CombatStillPlayer" - żołnierz celuje przez dłuższą chwilę.
"CombatToBinoc" - animacja sięgnięcia po lornetę. Trwa tylko chwilę.
"CombatToCrouch" - animacja klęknięcia. Trwa tylko chwilę.
"CombatToLying" - animacja położenia się. Trwa tylko chwilę.
"CombatToMedic" - animacja udzielania pomocy medycznej. Trwa tylko chwilę.
"CombatToPutDown" - animacja podkładania ładunku wybuchowego. Trwa tylko chwilę.
"CombatToStand" - animacja przejścia z trybu "AWARE", "COMBAT" albo "STEALTH" do trybu "SAFE" lub "CARELESS".
"CombatToTreated" - animacja otrzymywania pomocy medycznej (żołnierzowi, który może stać). Trwa tylko chwilę.
"CombatToWeapon" - animacja sięgnięcia po RPG. Trwa tylko chwilę.

Uwaga! Animacje "Combat..." pokazują żołnierzy w trybie "AWARE", "COMBAT" albo "STEALTH".

"CrouchDying" - animacja umierania w pozycji klęczącej. Trwa bez końca.
"CrouchToBinocCrouch" - animacja sięgnięcia po lornetkę z pozycji klęczącej. Trwa tylko chwilę.
"CrouchToCombat" - animacja powstania z pozycji klęczącej. Trwa tylko chwilę.
"CrouchToCrouchSprintF" - animacja poderwania się do biegu naprzód z pozycji klęczącej. Trwa tylko chwilę.
"CrouchToLying" - animacja położenia się z pozycji klęczącej. Trwa tylko chwilę.
"CrouchToWeapon" - animacja sięgnięcia po RPG w pozycji klęczącej. Trwa tylko chwilę.

"LyingCrawlF", "LyingCrawlL", "LyingCrawlR" - animacje czołgania się naprzód (F) na lewo (L) i na prawo (R). Trwa tylko chwilę.
"LyingDying" - animacja umierania w pozycji leżącej.
"LyingNoAim" - animacja leżącej postaci. Wywoływana tylko ze SwitchMove. Trwa bez końca. Postaci w tej animacji nie można zabić.
"LyingThrowGrenadeEnd" - animacja kończąca rzut granatem z pozycji leżącej, w przypadku użycia PlayMove następuje cała sekwencja rzutu.
"LyingToBinocLying" - animacja sięgnięcia po lornetkę z pozycji leżącej. Trwa tylko chwilę.
"LyingToCombat" - animacja powstania do pozycji stojącej (w trybie "AWARE", "COMBAT", albo "STEALTH").
"LyingToCombatRun" - ?
"LyingToCrouch" - animacja przejścia do pozycji klęczącej z leżenia. Trwa tylko chwilę.
"LyingToPutDownLying" - animacja podkładania ładunku wybuchowego z pozycji leżącej. Trwa tylko chwilę.
"LyingToTreatedLying" - animacja otrzymywania pomocy medycznej (żołnierzowi który nie może wstać). Trwa tylko chwilę.
"LyingToWeapon" - animacja sięgania po RPG z pozycji leżącej. Trwa tylko chwilę.

Uwaga! Przy użyciu polecenia SwitchMove w stosunku do animacji typu "Crouch..." lub "Lying..." spowoduje, że postacie nagle znajdą się w pozycji klęczącej lub leżącej. Przy użyciu PlayMove płynnie przejdą do tej pozy.

"MedicToCombat" - animacja kończąca udzielanie pomocy medycznej. Przy użyciu PlayMove odtwarzana jest cała sekwencja. Trwa tylko chwilę.

"PutDownLyingToLying" - animacja zakończenia podkładania ładunku wybuchowego z pozycji leżącej. Trwa tylko chwilę.
"PutDownToCombat" - animacja zakończenia podkładania ładunku wybuchowego. Trwa tylko chwilę.

Uwaga! Zauważ, że animacje "LyingToPutDownLying" i "PutDownLyingToLying" oraz "Combat ToPutDown" i "PutDownToCombat" przy użyciu PlayMove wyglądają tak samo (przy użyciu SwitchMove uzupełniają się).

"StandBase" - nie wiem co to daje (przy użyciu SwitchMove postać tylko drgnęła).
"StandDead", "StandDeadVer2", "StandDyingVer2" - animacje śmierci i umierania w pozycji stojącej w trybie "SAFE" albo "CARELESS".
"StandToBinocStand" - animacja sięgnięcia po lornetkę w trybie "SAFE" albo "CARELESS". Trwa tylko chwilę.
"StandToCombat" - animacja przejścia z trybu "SAFE" albo "CARELESS" do trybu "AWARE", "COMBAT" albo "STEALTH". Trwa tylko chwilę.
"StandWalkF" - animacja chodu. Trwa tylko chwilę.
"StandGetOutTank" - animacja wysiadania z czołgu lub APC. Działa tylko ze SwitchMove.

Uwaga! Animacje "Stand..." pokazują żołnierzy w trybie "SAFE" albo "CARELESS".

"TreatedLyingToLying" - animacja zakończenia otrzymywania pomocy medycznej z pozycji leżącej. Trwa tylko chwilę.
"TreatedToCombat" - animacja zakończenia otrzymywania pomocy medycznej. Trwa tylko chwilę.

Uwaga! Zauważ, że animacje "LyingToTreatedLying" i "TreatedLyingToLying" oraz "CombatToTreated" i "TreatedToCombat" przy użyciu PlayMove wyglądają tak samo (przy użyciu SwitchMove uzupełniają się).

"Weapon" - ?
"WeaponDead", "WeaponDying", "WeaponDyingVer2" - animacje śmierci i umierania żołnierza trzymającego RPG.
"WeaponToCombat" - animacja odłożenia RPG i powstania. Trwa tylko chwilę.
"WeaponToCrouch" - animacja odłożenia RPG i uklęknięcia. Trwa tylko chwilę.
"WeaponToLying" - animacja odłożenia RPG i położenia się. Trwa tylko chwilę.

2.243 Trzecia grupa animacji

Wreszcie trzecią najważniejszą grupę animacji stanowią animacje stworzone na potrzeby przerywników filmowych (lub z jakichś powodów nie umieszczone wśród animacji grupy drugiej).
Zwykle wywołać je można tylko komendą SwitchMove (chociaż zachowują się jakby użyto komendy PlayMove) i nie zakończają same swego działania. Zwykle też nie można zabić postaci podczas trwania tej animacji (należy mieć to na względzie umieszczając w misji, za pomocą animacji "OnChair", siedzącą na krześle osobę-cel do zlikwidowania) i należy (o ile jest to konieczne) użyć animacji "symulującej" śmierć.

"EffectCombatStand", "CombatStillV1" - Animacja żołnierza celującego przez chwilę w postawie pełnej napięcia (kiwa się lekko przestępując z nogi na nogę).
"EffectStandmove" - animacja stojącego zrelaksowanego żołnierza, który spokojnie się rozgląda. Działa tylko ze SwitchMove. Trwa bez końca. Podczas trwania animacji żołnierza nie da się zabić.
"EffectStandSitDown", "EffectStandSitDownVer1", "EffectStandSitDownVer2" - animacje powodujące, że żołnierz siada (przy użyciu SwitchMove nagle znajduje się w pozycji siedzącej). Jeżeli nie są w trybie "SAFE" lub "CARELESS" po chwili wstają. Podczas trwania animacji nie da się go zabić.
"EffectStandSitDownStill" - j.w tyle, że trwa bez końca nawet przy użyciu PlayMove.
"EffectStand", "EffectSitDownStand" - powodują powstanie postaci (służą np. do zakończenia animacji "EffectStandSitDownStill").
"EffectStandSalute", "EffectStandSaluteEnd" - animacja rozpoczęcia i zakończenia salutowania. Jeżeli jednostka jest w trybie "AWARE", "COMBAT" albo "STEALTH" animacja trwa chwilę (w przeciwnym przypadku trzeba ją zakończyć za pomocą "EffectStandSaluteEnd").
"EffectSaluteStand" - początek animacji "EffectStandSaluteEnd".
"EffectStandTalk" - animacja powodująca, że postać wygląda jakby rozmawiała (gestykuluje). Trwa dosyć długo, ale kończy się sama.
"EffectWeaponPanic" - animacja która ma rzekomo przedstawiać żołnierza przerażonego do tego stopnia, że zapomina jak użyć swej broni. Trwa bez końca. Wygląda dosyć dziwnie i jest niedopracowana (nie polecam używania).
"EffectStandStill" - ?

"FXangel", "FXangel2" - animacje które zastosowano w kampanii 1985 w stosunku do Angeliny (u innych postaci wygląda to dziwnie). Wywoływane jedynie za pomocą SwitchMove. Trwają bez końca.
"FXStandAtt" - animacja stojącego żołnierza (ręce z tyłu, nogi szeroko, sylwetka wyprostowana). Użyta w kampanii 1985 w pierwszej (treningowej) misji, podczas musztry. Wywoływana jedynie za pomocą SwitchMove. Trwa bez końca.
"FXStandAttVar1" - druga animacja stojącego żołnierza (niby na baczność, ale jakoś śmiesznie). Wywoływana jedynie za pomocą SwitchMove. Trwa bez końca.
"FXStandBug" - animacja stojącego żołnierza (ręce opuszczone, nogi szeroko). Wywoływana jedynie za pomocą SwitchMove. Trwa bez końca.
"FXStandStraight" - animacja stojącego na baczność żołnierza.
"FXStandhip" - animacja stojącego żołnierza (stoi swobodnie, kiwa się przez chwilę potem nieruchomieje). Wywoływana jedynie za pomocą SwitchMove. Trwa bez końca.
"FXStandToDip", "FXStandDip", "FXStandFromDip" - animacje przedstawiające kolejne fazy wykonania "pompek" przez żołnierza (położenie się, robienie pompek i powstanie).
"FXStandSur", "FXStandSurUniv" - animacje stojącego, poddającego się żołnierza (ręce w górze). Wywoływane jedynie za pomocą SwitchMove. Trwają bez końca.
"FXStandSurDown" - animacja powstającego i poddającego się żołnierza (ręce w górze). Wywoływana jedynie za pomocą SwitchMove. Trwa bez końca.
"FXStandSurDead" - animacja śmierci żołnierza, który wcześniej się poddał. Wywoływana jedynie za pomocą SwitchMove.
"FXStandToTable", "FXStandUnivTable", "FXStandFromTable" - trzy animacje tworzące sekwencję i przedstawiające kolejno: żołnierza siadającego na krześle, siedzącego (dosyć swobodnie nogi szeroko rozstawione) i powstającego (pozostaje z opuszczonymi rękami). Wywoływane jedynie za pomocą SwitchMove. Trwają bez końca (trzeba je kolejno wywoływać).
"FXStandRotateTable", "FXStandShowTable", "FXStandEndTable" - kolejne trzy animacje tworzące sekwencję. Przedstawiają kolejno: żołnierza podchodzącego do stołu, pokazującego coś na nim przez chwilę (najpewniej coś na mapie) i odchodzącego. Wywoływane jedynie za pomocą SwitchMove. Trwają bez końca (trzeba je kolejno wywoływać).
"FXStandToTel", "FXStandToTelHand", "FXStandTelLoop", "FXStandDropTel" - sekwencja animacji użyta do symulowania rozmowy telefonicznej. Kolejne animacje przedstawiają: podejście do telefonu i uchwycenie słuchawki, podniesienie jej i rozmowę w pozycji siedzącej, dalszą rozmowę (nieco inna animacja) oraz odłożenie słuchawki i powstanie. Wywoływane jedynie za pomocą SwitchMove. Trwają bez końca (trzeba je kolejno wywoływać).
"FXStandDangle" - animacja przedstawia (chyba) osobę rozpartą w fotelu i rozmawiającą przez telefon.

Uwaga! W przypadku większości animacji FX... postacie nie da się zabić podczas ich trwania (wyjątkiem są np. animacje siedzących postaci i salutowania). Zwykle też animacje nie kończą się same.

"OnChair" - animacja postaci siedzącej na krześle (prosto). Wywoływana jedynie SwitchMove. Trwa bez końca. Postaci podczas trwania animacji nie da się zabić.

"StandStrokeFist", "StandStrokeFistEnd" - animacje rozpoczęcia i zakończenia wymierzania ciosu ręką. W przypadku użycia PlayMove wyglądają tak samo. Trwają tylko chwilę.
"Stand" - ciekawa animacja. Działa z PlayMove. Postać stoi zrelaksowana lekko się kiwając. Trwa tylko chwilę.

"LyingStillV1" - animacja leżącej postaci, która zerka w bok. Trwa tylko chwilę.

"CombatStrokeGunEnd" - animacja kończąca cios kolbą, przy użyciu SwitchMove, lub pełną sekwencję ciosu przy użyciu PlayMove.

"CivilStillV1" - ciekawa animacja stojącego cywila (wgląda trochę jak naćpany, ręce opuszczone, kiwa lekko na boki), trwa bez końca.

"CommandEngageAtWill" - animacja dowódcy zezwalającego na atak wedle własnego uznania (Engage at will). Sygnalizuje on to ręką, machając do przodu i na boki. Działa tylko ze SwitchMove. Nie kończy się sama. Podczas trwania animacji postaci nie da się zabić.
"CommandFireAtWill" - animacja dowódcy zezwalającego na otwarcie ognia wedle własnego uznania (Fire at will). Sygnalizuje on to ręką, machając do przodu i na boki. Trwa tylko chwilę.
"CommandFormation" - animacja dowódcy nakazującego zmianę formacji oddziału. Sygnalizuje on to kręcąc ręką kółka w powietrzu. Trwa tylko chwilę.
"CommandForward" - animacja dowódcy nakazującego ruch naprzód. Sygnalizuje on to machając ręką do przodu. Trwa tylko chwilę.
"CommandHoldFire" - animacja dowódcy nakazującego wstrzymanie ognia. Sygnalizuje on to ręką, machając w górę i w dół. Trwa tylko chwilę.
"CommandStop" - animacja dowódcy nakazującego zatrzymanie się oddziału. Sygnalizuje on to ręką uniesioną w górę. Trwa tylko chwilę.

3. Elementy dodatkowe

Elementy dodatkowe stanowią różne triki (zwykle w postaci komend lub pętli).

3.10 Efektowne przejścia

Przejścia między ujęciami uzyskujemy umieszczając w skrypcie opisane na początku komendy:

TitleCut["","BLACK IN",n]
~n
TitleCut["","BLACK OUT",n]

Zamiast "BLACK..." można użyć "WHITE...", co daje efekt flasza aparatu fotograficznego (dawajcie krótki czas). Zalecam stosowanie przy krótkich dynamicznych ujęciach.

3.11 Zmiany pory dnia

Zmiany pory dnia uzyskujemy komendą SkipTime n gdzie n oznacza przesunięcie czasu wyrażone w godzinach. Zmienia się jedynie pogoda (zgodnie z prognozą) i pora dnia, jednostki pozostają na swoich miejscach.

3.12 Zmiany warunków atmosferycznych

Zmiany warunków pogodowych uzyskujemy komendami:

t SetFog v - zmienia stopień zamglenia do poziomu v (zakres od 0 do 1) w czasie t sekund.
t SetRain v - zmienia intensywność opadów do poziomu v (zakres od 0 do 1) w czasie t sekund.
t SetOvercast v - zmienia stopień zachmurzenia do poziomu v (zakres od 0 do 1) w czasie t sekund.

3.13 Przyspieszanie i spowalnianie upływu czasu

Zmiany prędkości upływu czasu uzyskujemy komendą SetAccTime v. Wartości v od 0 do 1 spowalniają upływ czasu, a wartości większe niż jeden przyspieszają (v=1 przywraca normalny upływ czasu).
Uwaga! Przy dużym przyspieszeniu jednostki nie zawsze zachowują się tak jak byśmy tego oczekiwali. Wyzwalacze mogą się nie uaktywnić jeżeli jednostka przebywa krótko w ich obszarze.

3.14 Nakładki

W OFP mamy możliwość nałożenia kilku rodzajów nakładek (overlays) w postaci telewizora, widoku z lornetki czy nakładki dającej efektu zdjęcia (czarno-białego). Do wywołania tych efektów należy użyć komend:

CutObj ["TvSet","PLAIN"] lub TitleObj ["TvSet","PLAIN"] - nakładka typu telewizor.
CutRsc["Binocular","PLAIN"] lub TitleRsc["Binocular","PLAIN"] - nakładka typu lornetka.
CutRsc["Foto","PLAIN"] lub TitleRsc["Foto","PLAIN"] - nakładka typu fotografia.
(Nie dostrzegam różnic pomiędzy działaniem komend Cut... i analogicznych Title...)

Powrót do normalnego widoku uzyskujemy wpisując komendę odpowiednio:

CutObj ["default","PLAIN"] lub TitleObj ["default","PLAIN"]
CutRsc["default","PLAIN"] lub TitleRsc["default","PLAIN"]

3.15 Przybliżanie i oddalanie widoku

Zbliżenia (zoom) i oddalenia (unzoom) kamery uzyskujemy komendą _cam CamSetFOV z, która powoduje ustawienie zbliżenia z (gdzie dla z od 0 do 1 otrzymujemy zbliżenie, a dla z większych o 1 oddalenie. Użycie z=1 przywraca domyślne zbliżenie) dla kamery skojarzonej ze zmienną lokalną skryptu _cam.
komenda wymagają potwierdzenia za pomocą _cam CamCommit n (dla n=0 przejście jest natychmiastowe).

3.16 Ustawianie kamery względem obiektu

Gdy nie jesteśmy w stanie przewidzieć jak będzie zwrócony obiekt, a chcemy np. mieć ujęcie z przodu przydaje się następujący fragment kodu:

_dir = GetDir obiekt
_cam CamSetTarget obiekt
_cam CamSetRelPos [sin(_dir)*2,cos(_dir)*2, 0.5]
_cam CamCommit 0

Umieści on kamerę 2 metry przed obiektem na wysokości pół metra.

3.17 Obracanie kamery wokół punktu

Obrót kamery wokół obiektu realizuje następująca pętla:

_cam CamSetTarget obiekt
_cam CamCommit 0
;początkowy kąt ma wartość 0, ale może być inna
_angle = 0
#Loop
;wartość 50 określa dystans do obiektu, a 30 wysokość z jakiej filmujemy (a więc pośrednio kąt pod jakim filmujemy)
_cam CamSetRelPos [sin(_angle)*50,cos(_angle)*50,30]
_cam CamCommit 0
;przyrost kąta w jednostce czasu-zmiana na większy np. _angle=_angle+10 przyspieszy obrót.
;Odejmowanie spowoduje obrót w stronę przeciwną (trzeba wtedy zmienić warunek wykonywania pętli).
_angle=_angle+2
~0.02
;dopóki kąt jest mniejszy od 360 stopni (pełen obrót wokół obiektu) pętla jest wykonywana
;oczywiście wartość może być inna np. 720 da nam dwa pełne obroty.
?(_angle<360):Goto "Loop"

Pętla zostanie wykonana 180 razy co potrwa około 3,6 sekundy (180*0,02sek).
Element ten został użyty w przykładzie nr 3.

3.18 Kamera towarzysząca

Ciekawym efektem jest kamera towarzysząca obiektowi będącemu w ruchu. Efekt ten uzyskujemy za pomocą następującej pętli:

_cam CamSetTarget obiekt
_cam CamCommit 0
_i=0
#Loop
_i=_i+1
_cam CamSetRelPos [0,10,5]
_cam CamCommit 0
~0.02
?(_i<200):Goto "Loop"

Pętla ta będzie utrzymywać kamerę w punkcie (względem obiektu) ustalonym za pomocą komendy CamSetRelPos.
Powyższa pętla będzie wykonywana przez ok. 4 sekundy (200*0,02sek).
Pozycja kamery względem obiektu nie zmienia się wraz ze zmianą kierunku jego ruchu. By to uzyskać potrzeba poniższej pętli:

_i=0
#Loop
_ox = GetPos obiekt Select 0
_oy = GetPos obiekt Select 1
_kierunek = GetDir obiekt
;kamera znajdzie się 3 metry za obiektem na wysokości 3,5 metrów
_cam CamSetPos [_ox+sin(_kierunek)*(-3),_oy+cos(_kierunek)*(-3),3.5]
;kamera wycelowana będzie 10 metrów przed obiekt na wysokość 3.5 metra
_cam CamSetTarget [_ox+sin(_kierunek)*10,_oy+cos(_kierunek)*10,3.5]
_cam CamCommit 0
~0.02
?(_i<200):Goto "Loop"

Niestety w przypadku pojazdów z wieżą kierunek dotyczy kierunku jazdy a nie kierunku ustawienia wieży.
Powyższa pętla będzie wykonywana przez ok. 4 sekundy (200*0,02sek).

3.19 Kamera towarzysząca wykonująca obrót

Możliwe jest połączenie dwóch poprzednich efektów w jeden za pomocą pętli:

_cam CamSetTarget obiekt
_angle = (GetDir obiekt) + 90
_angleEnd = _angle - 180
#Loop
;kamera wykona obrót pozostając w odległości 20 metrów od obiektu i na tej samej wysokości
_cam CamSetRelPos [sin(_angle)*20,cos(_angle)*20,0]
_cam CamCommit 0
~0.02
_angle = _angle-1
?(_angle>_angleEnd):Goto "Loop"

Pętla zostanie wykonana 180 razy co potrwa około 3,6 sekundy (180*0,02sek). Kamera wykona pół obrót tj. przejdzie z jednej strony obiektu na drugą.

Przykłady:
- Misja nr 1,
- Misja nr 2,
- Misja nr 3.

Napisał: ALDEROUS



Wejdź na forum Wejdź na stronę Armed Assault Center PL