Základy programování v OFP
Z Armed Assault nápověda
Obsah |
Základy programování v OFP
SKRIPTY
V tomto článku se pokusím čtenářům ukázat základy programování ve hře Operace Flashpoint (potažmo i v Armed Assault). Pro začátek budu předpokládat alespoň minimální zkušenost s editorem misí, címž je myšlena schopnost vložit jednotku, vytvořit spínač se základními podmínkami (západ nepřítomen apod.).
Co je to skript?
No ale začněme pěkně od začátku. Tím, že si v editoru uložíte váš výtvor dojde k vytvoření adresáře v /Users/vase_jmeno_v_ofp/missions/ a to v podobě nazev_mise.zkratka_ostrova. V tomto adresáři se vytvoří soubor mission.sqm, jenž obsahuje všechny důležité informace z editoru jako seznam skupin, jména a pozice objektů, jejich typy a různá další všemožná nastavení. No a právě do tohoto adresáře (případně do jeho podadresářů) se vkládají skripty. OFP používá skripty s koncovkou sqs a sqf. O souborech sqf se v tomto článku nebudu zmíňovat, protože jde o techniku, které by se měli věnovat spíše pokročilejší uživatelé. Pro úplné základy bychom si měli vystačit jen s sqs soubory.
Jak vytvořím skript?
Bohužel OFP neobsahuje žádný integrovaný editor skriptů, takže je nutné jej vytvořit externě nejlépe v některém z vašich oblíbených textových editorů. Jen si dejte pozor, aby vám jej například notepad (poznámkový blok) neuložil souboru ve tvaru nazev_skriptu.sqs.txt (což je častá chyba začátečníků). Příkazy se do sqs souborů zapisují na řádky pod sebou (narozdíl od sqf souborů, kde toto neplatí a kde jsou odděleny středníkem). Každý příkaz by měl být umístěn na jeden řádek (až na speciální většinou podmínkové konstrukce). Rozhodně není od věci do skriptu umístit i nějakou tu poznámku. Ta se zapisuje za středník.
Ukažme si takový jednoduchý skript, kterým vybavíme vojáka zbraní. Soubor pojmenujeme "vybav_vojaka_jednoduse.sqs"
; odeberu vojakovi vsechno vybaveni RemoveAllWeapons vojak ; pridam mu nejdrive zasobnik do zbrane vojak addMagazine "FALMag" ; a pak samotnou zbran. Diky tomu ji bude mit hned od zacatku nabitou. vojak addWeapon "FAL" ; a jeste mu dam zasobnik, at ma neco do zasoby vojak addMagazine "FALMag"
Jak je vidět, jde o skript, který vybaví objekt pojmenovaný v editoru jako vojak.
Jak spustit skript?
No dobrá, skript už máme, ale jak donutit engine ho spustit? Je několik možností jak toho docílit. Rozhodně je dobré vědět, že OFP samo při spuštění mise (či intra) zkoumá, zda není v adresáři mise přiložen určitý soubor a pokud je, pak ho sám při inicializaci spustí a my se posléze už nemusíme o spouštění starat. Těmito soubory jsou init.sqs, initintro.sqs a exit.sqs. První se spustí při spuštění samotné mise, druhý při úvodním intru a třetí po ukončení mise, ještě před debrifiengem. Takže pokud chcete provést nějaké definice či nastavení hry na začátku při spuštění mise, pak je jednoznačně nejlepší využít souboru init.sqs. Další možností jak spustit sqs soubor je pomocí příkazu exec. Příkaz je možné vložit například v inicializaci vojáka či do řádku "po aktivaci" ve spínači a nebo samozřejmě i do obsahu již zmiňovaného skriptu init.sqs. Jako takovou menší poznámku bych rád upozornil, že pokud spustíme skript v inicializaci hráče a inicializaci například nepřátelského vojáka, pak ke spuštění skriptu z inicializačního okénka hráče dojde dříve. Tím se dá vyvarovat situaci, kdy například na začátku skriptu vytváříme kameru, která ukazuje budoucí bojiště a tato kamera se vytvoří až po chvíli (což je přesně ta velmi nepříjemná půl sekunda, kdy problikne hra nejdříve na hráče a až posléze dojde k pohledu na vytvořenou scénu). V tomto případě je jednozačně výhodnější vložit spuštění souboru buď do inicializace hráče nebo úplně nejlépe přímo do init.sqs. A teď k samotnému spuštění. Příkaz exec má syntax: parametr exec "nazev_souboru.sqs" Např.
[vojak1,vojak2,vojak3] exec "vybav_vojaky.sqs"
nebo
vojak exec "vybav.sqs"
a jako poslední poslední možnost
[] exec "ukaz_video2.sqs"
Schválně jsem zvolil tyto tři možnosti, protože je vidět, že se ve volání vždy liší první parametr zasílaný souboru. Začněme od konce. V tom případě dojde ke spuštění souboru ukaz_video2.sqs a souboru nejsou předány žádné parametry (respektive je mu předáno prázdné pole). V druhém případě je předán parametr vojak, což je název objektu, vloženého a pojmenovaného v editoru. Takto je možné vytvořit si soubor, který postupně vybaví každého vojáka s jehož jménem skript zavolám. Zaslaný parametr je ve skriptu přítomen jako lokální proměnná "_this", která je přesně toho typu jakým došlo k zavolání skriptu.
Příklad souboru, který by vybavil vojáka, jehož jméno bylo zadáno jako parametr skriptu:
; Obsah souboru "vybav.sqs" ; odeberu vojakovi vsechno vybaveni RemoveAllWeapons _this ; pridam mu nejdrive zasobnik do zbrane _this addMagazine "FALMag" ; a pak samotnou zbran. Diky tomu ji bude mit hned od zacatku nabitou. _this addWeapon "FAL" ; a jeste mu dam zasobnik, at ma neco do zasoby _this addMagazine "FALMag"
Každý objekt, který bude předán skriptu jako první parametr bude vybaven přesně podle našich požadavků.
V třetím případě (respektive i v prvním) je zasláno skriptu jako parametr pole (co je to pole bude vysvětleno později). Toto pole obsahuje tři objekty - vojak1, vojak2 a vojak3. I toto pole je ve skriptu přítomné jako parametr _this. Abychom se dostali k samotným prvkům pole je nutné využít příkazu select, díky němuž si můžeme vybrat jednotlivé prvky pole. Select má syntaxi: nazev_pole select poradove_cislo Jen upozorním, že pole je číslováno od nuly, takže vojak1 je dostupný jako "_this select 0", vojak2 jako "_this select 1" a vojak3 jako "_this select 2"
Teď by neměl být problém vytvořit a zavolat jakýkoliv sqs skript.
PROMĚNNÉ
Nyní se dostáváme k věci, bez které se s největší pravděpodobností při programování v OFP neobejdete. Jde o proměnné. OFP rozlišuje dva základní typy proměnných. Jde o lokální a globální proměnné. Rozdíl je prostý, jména lokálních proměnných vždy začínají podtržítkem a jsou přístupná a přítomná pouze v rámci skriptu ve kterém byly vytvořeny. Oproti tomu globální proměnná je přístupná ve všech sqs skriptech.
Příklad. soubor: definice.sqs obsah:
_lokalni_pojmenovani = vojak globalni_pojmenovani = vojak
soubor:upravy.sqs obsah:
removeallweapons globalni_pojmenovani _lokalni_pojmenovani addweapon "m16"
soubor: init.sqs obsah:
[] exec "definice.sqs" [] exec "upravy.sqs"
Výsledkem spuštění mise s těmito třemi skripty bude odebrání všech zbraní objektu pojmenovanému jako "vojak" (globalni_pojmenovani ze skriptu definice.sqs je přístupné i v upravy.sqs), ale nedojde k přidání zbraně M16, protože hodnota _lokalni_pojmenovani vytvořené v souboru definice.sqs už není v souboru upravy.sqs přítomná.
Jak jste si mohli všimnout tak v OFP se všechny proměnné inicializují přiřazením hodnoty. Pokud se ale dotážete na hodnotu proměnné, které ještě nebyla vytvořena pak dojde k navrácení řetězce "scalar bool array string 0xfcffffef" jenž označuje nedefinovanou proměnnou (čehož se dá i využít v případě zjišťování, zda proměnná byla již vytvořena).
Příklad:
; vytvoření pole pole_vojaku = [vojak1,vojak2,vojak3] ; vytvoření číselné proměnné sila = 2 ; vytvoreni promenne obsahujici pocet prvku v poli "pole_vojaku" pocet_vojaku = count pole_vojaku ; zjisteni pomyslne sily vojaku celkova_sila = pocet_vojaku * sila
OFP dokáže pracovat s proměnnými několika typů.
TYPY PROMĚNNÝCH
Jak již bylo zmíněno dříve, tak proměnné mohou být několika typů. Mezi naprosto základní a nejdůležiější typ patří rozhodně objekt. Objektem jest každá věc, kterou jsme umístili v editoru (či vytvořili například pomocí příkazů createvehicle). Objektem tak může být voják, tank, letadlo i prázdný sud. Většina příkazů OFP enginu je určena právě pro práci s objekty. Objekty jsou často spojeny vazbou v editoru do skupin. Některé příkazy pracují jen se skupinami. Pro zjištění vazby mezi skupinami a jejími objekty jsou využívány příkazy Group a Units. Mezi další základní datové typy patří řetězec (_text="Ahoj světe", hint _text), celé číslo (_pocet=4) i reálné číslo (_a=5.4), boolean (true/false neboli pravda/nepravda) či null neboli nedefinovaný typ. Posledním základním již zmíněným typem je pole. Jde seznam prvků nejlépe stejného typu, ale to není podmínkou. Do pole si tak můžete sdružovat jednotky, které nejsou ve stejné skupině, ale chcete na ně aplikovat stejné příkazy. Pole je možné vytvářet i vícerozměrné a to zápisem _pole = [[1,1],[2,2]];
PŘÍKAZY PRO VĚTVENÍ PROGRAMU
Nyní se dostáváme ke složitějším věcem a to možnostem větvení chodu skriptu, které OFP nabízí. Samotný skript je možné na základě určitých parametrů různě přeskakovat či opakovat. K tomu slouží příkazy určené právě pro větvení programu.
Začněme primitivním příkazem editoru a to "goto" Tento příkaz odskočí ve skriptu na požadovanou "kotvu", která je ve skriptu zapsaná ve tvaru #nazev_kotvy Příklad jednoduché smyčky:
#zacatek vojak addmagazine "m16" goto "zacatek"
Tento naprosto nepraktický skript bude donekonečna přidávat vojákovi zásobníky (a pravděpodobně dojde k vytuhnutí OFP či celého systému). Je tedy nutností zajistit, aby k tomu nepříjemnému vytuhnutí nikdy nedošlo. Toho nejlépe docílíme tím, že smyčku pokud možno v patřičném momentě ukončíme nebo zajistíme, aby nedošlo k přehlcení systému. V případě, že opravdu chceme opakovat nějaký skript dokenkonečna, pak je nejlepší vložit časovou prodlevu do skriptu. Ta se vloží pomocí tzv. vlnky a časového údaju v jednotkách sekund, po který má skript vyčkat ve svém provádění.
#zacatek2 vojak addmagazine "m16" ; vyckej jednu sekundu ~1 goto "zacatek2"
Následující skript je sice stále nepraktický, ale nedojde k přetížení systému díky neustálému přidávání zásobníků. Dochází k tomu "jen" každou sekundu.
Často budeme chtít chování ovlivňovat na základě některých událostí a k tomu nám do začátku nejlépe poslouží dotaz zapisovaný jako otazník (?) ve tvaru ?(dotaz):prikazy_k_provedeni_pri_splneni_oddelene_strednikem Dejme tomu, že chceme aby se předchozí smyčka provedla jen třikrát, pak bude skript vypadat.
_pocet=0 #zacatek3 vojak addmagazine "m16" ; zvetsim pocitadlo o jedna _pocet = _pocet + 1 ; vyckej jednu sekundu ~1 ; pokud bude lokalni promenna _pocet mensi jak 3 pak dojde ke skoku na kotvu "zacatek3" v opacnem pripade pokracuje skript dal ?(_pocet<3):goto "zacatek3" exit
Pokud bychom chtěli skript nějak pozastavit dokud není splněna určitá podmínka (například pojmenovaná vojak_zije), tak můžeme buď zavést složitou smyčku:
#kontrola ~0.01 ?(not vojak_zije):goto "kontrola"
A ne bo využít speciálního zápisu, které OFP nabízí. Jde o zavináč (@). Díky němu engine provádějící skript vyčká do splnění podmínky a tak místo předchozích tří řádků stačí jednoduše napsat:
@vojak_zije
Skript v tomto momentě zastaví a vyčká na přiřazení booleanovské hodnoty true proměnné "vojak_zije"
Obdobou tohoto příkazu je If... Then ... Else Tento má syntax If (podminka) then {prikazy_pri_splneni_podminky_oddelene_strednikem} else {prikazy_pri_nesplneni_podminky_oddelene_strednikem} Příklad:
if (alive vojak) Then {vojak addweapon "m16";vojak addmagazine "m16"} Else {removeallweapons vojak}
Středníky jsou v tomto případě nutné a jejich nepřítomnost je častou opakovanou chybou.
Další konstrukcí, kterou můžeme pro větvení využít je cyklus while ... do ... Syntaxe je while {podminka} do {prikazy_ktere_se_provadi_dokud_je_podminka_splnena} Příklad:
while {_i<10} do {_i=_i+1}
Tato konstrukce vytváří smyčku, která se provádí dokud není splněna zadaná podmínka.
Na závěr bych uvedl příkaz foreach, který aplikuje vložené příkazy na všechny prvky předaného pole. Každý tento prvek je pak ve skriptu přítomný jako _x
Syntaxe tedy je
{prikazy} foreach pole
Příklad:
{_x setunitpos "up"; _x setdamage 0} foreach (units player)
Je možné tyto konstrukce i kombinovat dohromady, takže můžete narazit i na trochu složitější konstrukce jako je například:
while {_n < _max} do {
_dist = _start distance (_Enemy_base select _n);
if (_dist < _nej) then {
_nej = _dist;
_cil = (_Enemy_base select _n)
};
_n = _n + 1
};
Čímž už se dostáváme opravdu k složitějším věcem. Myslím, že s tímto jako se základy byste měli dlouho vystačit.

