Tutorial 30 - Podmínky
Autor : Didymos
Download = Tento tutorial + ukázka

 

Muttley nás požádal o napsání tutoriálu, který by se zabýval podmínkami. Toto je ale velmi těžký úkol, protože podmínek může být opravdu mnoho. Z E-mailu, který Muttley napsal, jsem pochopil, že mu jde o podmínku, kterou vyskočí z nějaké smyčky. Na začátek bychom si mohli slovo podmínka nějakým způsobem definovat. Podmínka je v podstatě věc, která podmiňuje něco jiného, tudíž je na něčem jiném závislá. Bez toho něčeho, co podmínka podmiňuje, by byla podmínka zbytečná. Jednoduše řečeno se nestane daná věc, dokud se nenaplní určitá podmínka nebo naopak se bude jistá věc dít, dokud se nenaplní podmínka pro její skončení. Co se ale editace v OFP týče, tak tady bychom našli opravdu velmi mnoho podmínek a v podstatě by se dalo říct, že celá hra je na podmínkách založená, protože dokud nesplníte úkol (což je také podmínka), tak se např. neukončí mise. Teď bych mohl do nekonečna pokračovat ve výčtu podmínek. Jak jsem ale psal na začátku, tak dotaz, který byl vznešen se týká nějaké určité podmínky. Já bych to převedl na kamerové podmínky, kde se to dá alespoň trochu ukázat. V této souvislosti mě napadá asi ta nejjednodušší podmínka, kterou je podmínka časová, vytvoříme si kameru, která bude z pozice objekt1 sledovat objekt2:

 

_CameraPos = getpos objekt1
_cmx = (_CameraPos select 0)
_cmy = (_CameraPos select 1)
_cmz = (_CameraPos select 2) + 1
_cam = "camera" CamCreate [_cmx,_cmy,_cmz]
_cam CameraEffect ["Internal","back"]
_cam CamCommit 0
_cam CamSetTarget objekt2
_cam CamSetFov 0.5
_cam CamCommit 0
@camCommitted _cam
~4

 

To celé bude probíhat po dobu 4 sec. Což je právě podmínka úplně na konci v posledním řádku. (~4)
Budeme pokračovat dál, kdy kamera sleduje vozidlo (pojmenované vozidlo, z pozice hacko1) a chcete, aby ho sledovala tak dlouho, dokud ho neopustí (v tomto případě) vojak. Když hned pod to přidáte podmínku časovou (~3), tak tam kamera vydrží ještě další tři vteřiny. Hned máte jistotu, že se kamera nepředběhne a že tam vydrží opravdu do doby, než se nenaplní podmínka opuštění vozidla a následně ještě pak 3 sec. jak je vidět tady:

 

_CameraPos = GetPos hacko1
_cmx = (_CameraPos select 0) - 50
_cmy = (_CameraPos select 1) + 30
_cmz = (_CameraPos select 2) + 1.7
_cam CamSetPos [_cmx,_cmy,_cmz]
_cam CamSetTarget boing1
_cam CamSetFov 0.4
_cam CamCommit 0
@camCommitted _cam
@not (vojak in vozidlo)

 

Můžete zadat do posledního řádku kamery např.:

 

@neco

 

kde neco je proměnná, která dokud nenabude hodnoty true, nebude vytvořena podmínka pro pokračování. Jakým způsobem, jestli do spínače nebo scriptu nebo kamkoli jinam hodnotu něco=true zadáte záleží už jen na Vás. Důležité ale je někde na začátku zadat hodnotu neco na false. (neco=false) Nejlépe do "init.sqs".
Jestliže napíšete do posledního řádku tuto podmínku:

 

@not alive vojak

 

Kamera bude sledovat zadaný objekt do doby, dokud bude žít vojak. (not alive vojak) Dalším jednoduchým příkladem je podmínka, kdy bude kamera sledovat jednotku dem1 z pozice objekt do doby, než splní nějaký dříve zadaný příkaz. Přímo tady jsem zadal jednotce dem1 příkaz k položení nálože (dem1 fire ["put", "pipebomb"] ), až to dokončí (@unitready dem1) pokračuje dalším příkazem a to přesunem k nějakému objektu v editoru podle čísla ID. (dem1 move [GetPOs object 137398 select 0, GetPOs object 137398 select 1]) Poté tam kamera vydrží ještě další dvě vteřiny, (~2) než bude pokračovat.

 

_CameraPos = GetPos objekt
_cmx = (_CameraPos select 0) + 5
_cmy = (_CameraPos select 1) - 5
_cmz = (_CameraPos select 2) + 1
_cam CamSetPos [_cmx,_cmy,_cmz]
_cam CamSetTarget dem1
_cam CamSetFov 0.7
_cam CamCommit 0
@camCommitted _cam
dem1 fire ["put", "pipebomb"]
@unitready dem1
dem1 move [GetPOs object 137398 select 0, GetPOs object 137398 select 1]
~2

 

Dalším příkladem je ukončení kamery zachycené za vozidlo:

 

#let _CameraPos = getpos ah
_cmx = (_CameraPos select 0) +2
_cmy = (_CameraPos select 1) - 5
_cmz = (_CameraPos select 2) + 1.7
_cam = "camera" CamCreate [_cmx,_cmy,_cmz]
_cam CameraEffect ["Internal","back"]
_cam CamSetTarget ah
_cam CamSetFov 0.7
_cam CamCommit 0
~0.01
? NOT (zrus) : goto "let"

 

Kamera bude sledovat vozidlo ah do doby, než se proměnná zrus nenaplní na true. Nesmíme opět zapomenout někde na začátku skriptu zanést: zrus=false! (init.sqs)
Na další ukázky podmínek použiji jednu starší Ruprtovu ukázkovou misi, na které je to zcela zřejmé. Máme tu tři vozidla: hummer, motorku a letadlo. Kamera začíná zavěšená za hummrem (v1) a to takto:

 

_CameraPos = getpos v1
_cmx = _CameraPos select 0
_cmy = _CameraPos select 1
_cmz = _CameraPos select 2
_cam = "camera" CamCreate [_cmx - 20,_cmy - 200, 1.5]
_cam CameraEffect ["Internal","Front"]
_cam CamSetTarget v1
_cam CamSetFov 0.5
_cam CamCommit 0
@CamCommitted _cam

 

#Jizda1
_cam CamSetRelPos [0, -10, 1.5]
_cam CamCommit 0
~0.01
? (v1 Distance v2) > 35 : GoTo "Jizda1"

 

Jak je vidět, tato kamera bude následovat hummer a to do doby, než se podmínka naplní. Tady ta doba nastane, když se vozidlo v1 (hummer) přiblíží k vozidlu v2 a to na vzdálenost 35m. Po naplnění této podmínky bude kamera sledovat vozidlo v2 v našem případě motorku.

 

_cam CamSetRelPos [0, 9, 1.5]
_cam CamSetTarget v2
_cam CamCommit 1
@CamCommitted _cam

 

_mytime = _time
#Jizda2
_cam CamSetRelPos [0, 10, 1.5]
_cam CamCommit 0
~0.01
? _time < (_mytime + 15): GoTo "Jizda2"

 

Zde se podmínka naplní po uplynutí času 15 sec. Po té následuje pomalé a plynulé přiblížení k letadlu a1:

 

_cam CamSetTarget a1
_cam CamCommit 4
@CamCommitted _cam

 

dive = 0
_dy = - 300
_dz = 0 - (GetPos a1 Select 2) + 1.5
#Approach
_cam CamSetRelPos [-20, _dy, _dz]
_cam CamCommit 0
@CamCommitted _cam
~0.01
_dy = _dy + 1
_dz = _dz + 1
? _dz >= 0: _dz = 0
? _dy < -20 : GoTo "Approach"

 

#Loop1
_cam CamSetRelPos [-20, -20, 0]
_cam CamCommit 0
~0.01
? dive == 0 : GoTo "Loop1"

 

Tady ukázková mise končí. Tímto jsem chtěl naznačit, že opravdu záleží na vaší fantazii, kolik podmínek tady vytvoříte. Je doufám jasné, že se podmínky nevztahují pouze na kamery, už v samotném spínači je kolonka s názvem podmínka, která je řekl bych hodně podobná s těmito podmínkami pro kameru. Když si třeba vytvoříte spínač, který bude mít v kolonce Podmínka:

 

west1 distance east1<20

 

a do pole Pří aktivaci zadáte:

 

[west1, east1] exec "poplach.sqs"

 

pak se stane to, že v případě, kdy se přiblíží west1 k east1 na vzdálenost 20m., spustí se skript s názvem poplach. Co zadáte do tohoto skriptu, už záleží na vás. Může to být třeba pouhý text, ale s trochou důvtipu přidají podmínky tohoto typu na kvalitě celé mise. Pozor ale na to, aby se vám jednotlivé podmínky neprolínaly a především na to, aby nebyla nějaká podmínka závislá na dokončení celé mise!!! Naopak, jestliže je dokončení mise závislé na životě nějaké jiné osoby, zadáte do pole Podmínka ve spínači:

 

not alive vip

 

a do pole Typ zadáte Prohra. Tady se stane to, že v případě ztráty vip se mise ukončí prohrou. Pak už stačí vytvořit scutscénu Outro - prohra.
Tohle je o podmínkách odemě vše. Teď tu mám ještě doplněk Ruprta o strukturovaných podmínkách, které jsou od verze 1.75.

 

Strukturovaná podmínka

S verzí hry 1.75 a vyšší nám BIStudio dalo do rukou nový nástroj na vytváření podmínek a to strukturovanou funkci If… Then …Else a While … Do.

 

Každý skriptovací příkaz nebo funkce v souborech skriptů *.SQS (v to počítaje i podmínky) je vykonán pouze v případě, že příkaz včetně jeho parametrů a argumentů je umístěn na jednom řádku, případně může být uvedeno na jednom řádku více příkazů, musí však být odděleny středníkem. Nelze tedy vykonat jeden příkaz zapsaný v jednom řádku s parametrem uvedeným v jiném řádku. Tento způsob programového zpracování příkazů se nazývá "řádkově založený skript" (Line Based Skript). Tento způsob však do značné míry omezuje programovací možnosti daného jazyka.
Oproti tomu výše uvedené strukturované funkce If… Then … Else a While… Do mohou být vykonány i když jsou zapsány na neomezeném počtu řádků. Toto se nazývá "víceřádkově založený script" (Multiline Based Skript) V tomto případě však je nutné funkce umístit do souboru s příponou SQF nikoli SQS. Zároveň berte na vědomí, že ne všechny výrazy skriptovacího jazyka hry OFP mohou být ve skriptech funkcí vykonány, např. nelze v nich použít prodlevu (~číslo nebo &číslo), neboť funkce je vždy vykonána jako celek, nikoli jako soubor několika příkazů.
Tyto funkce pak mají poněkud odlišnou syntaxi :

 

If (podmínka) Then {výraz1} Else {výraz2}
| podmínka ->| | tělo funkce -------------->|

 

Přeloženo do češtiny to znamená:
Pokud (podmínka) vrátí TRUE pak(THEN) udělej {výraz1}, jinak (ELSE) udělej {výraz2}. Výrazy 1 i 2 musí být uzavřeny v kudrnatých závorkách (správně) nebo v uvozovkách (nedoporučuji).

 

While "podmínka" Do {výraz} | podmínka ------>| | tělo funkce->|

 

Přeloženo do češtiny to znamená :
Pokud "podmínka" vrací TRUE vykonávej pořád dokola {výraz}. Maximální počet opakování je stanoven na 10.000. Pokud se smyčka zopakuje 10.000x a podmínka stále vrací TRUE, smyčka se ukončí a je zobrazena chybová zpráva.

 

Příklad #1 - Funkce If … Then…Else umístěná v souboru *.SQS.
Pokud je tato podmínková funkce umístěná v souboru .SQS chová se naprosto identicky jako dosud známé ? výraz : výraz .

 

_query = 5
_zk = 0
_zk1 = 5
_zk2 = 10
If (_query = = 5) Then {_zk = _zk1 + _zk2} Else {_zk = _zk2 - _zk1}

 

Výsledkem je že : _zk = 15

 

Naprosto stejného výsledku však dosáhnete i použitím starého dobrého :

 

? _query = = 5: _zk = _zk1 + _zk2; Goto "Skip"
_zk = _zk2 - _zk1
#Skip
Příklad #2 - Funkce If … Then…Else umístěná v souboru *.SQF.

 

Soubor funkcí *.SQF nelze spouštět pomocí příkazu Exec. Pro vykonání kódu zapsaného do souboru *.SQF je nutno použít též nově implemtované příkazy PreprocessFile nebo LoadFile, který na své místo v souboru *.SQS dosadí obsah volaného souboru *.SQF, anebo příkaz Call v kombinaci s PreprocessFile nebo LoadFile, který rovnou kód v souboru *.SQF vykoná.

 

Kód souboru *.SQS
_query = 5
_zk = 0
_zk1 = 5
_zk2 = 10
[] Call PreprocessFile "zkouska.sqf"

 

Kód souboru ZKOUSKA.SQF

 

If (_query = = 5) Then
{
_zk = zk1 + zk2
}
Else
{
_zk = _zk2 - _zk1
}
Výsledkem je že : _zk = 15

 

Protože v souborech funkcí *.SQF nemá konec řádku žádný speciální význam, musíte, pokud bude výraz obsahovat více příkazů, každý řádek výrazu ukončit středníkem, např. takto :

 

If (_query = = 5) Then
{
_zk = zk1 + zk2;
Player SetDamage 0
}
Else
{
_zk = _zk2 - _zk1
}
Výsledkem je že : _zk = 15 a hráč bude mít hodnotu poškození 0.

 

Vše co je zpracováno v souboru *.SQF je zpracováno jako řetězec. Nelze proto použít příkaz PreprocessFile nebo LoadFile jako samostatný příkaz v souboru scriptu, ale pouze jako část (výraz) funkce If … Then … Else nebo While … Do, nebo jako tělo příkazu Call. Naopak vše co je uvedeno v souboru *.SQF lze použít jako řetězcový parametr nebo argument jakékoli skriptovací funkce nebo příkazu, který takový argument podporuje. Jinými slovy, pokud by jste ve svém souboru skriptu uvedli např. :

 

TitleText [PreprocessFile "zkouska.sqf", "PLAIN"]

 

Pak se vám podle předchozího příkazu vypíše na obrazovku :

 

If (_query = = 5) Then{ _zk = zk1 + zk2}Else{ _zk = _zk2 - _zk1}

 

Příklad #3 - Funkce While… Do umístěná do souboru *.SQF.

 

Tento příklad doplní do hráčovi skupiny tolik vojáků, aby jich celkem celá skupina obsahovala 10.

 

Kód souboru *.SQS :
[] Call PreprocessFile "zkouska1.sqf"

 

Kód souboru ZKOUSKA1.SQF :
While "(Count Units Group Player) < 10" Do
{
"SoldierWB" CreateUnit
[
[
(Position Player Select 0) + Random 5,
(Position Player Select 1) + Random 5,
Position Player Select 2
],
Group Player
]
}

 

Tolik tedy od Ruprta. Jeslti pochopíte tohle, tak si myslím, že už není potřeba pokračovat a mě už stačí vám jen popřát hodně trpělivosti. Na závěr snad ještě poslední podmínku:

 

Abyste pochopili co tady píšu, musíte si to celé přečíst a zřejmě to nebude stačit jednou. (věta účelová, ne podmínková)

 

Didymos