JEŽURŮV TUTORIÁL O PRÁCI S DIALOGY V OFP (verze 2.0)

Úvod

Dialogy jsou VELICE užitečným nástrojem v editaci misí a jejich pochopení vám rozšíří možnosti ve tvorbě misí stejně (ne-li víc) jako další nové příkazy od verze 1.75. To mě motivovalo k tomu, abych napsal tento tutoriál. Je to vlastně doplněná forma Ruprtova tutoriálu, který můžete najít v jeho OFP EditorHelpu.

Toto je druhá verze mého původního tutoriálu. Seznam úprav jsem nikde nevypisoval, protože se změnilo v podstatě všechno... Druhá verze je navíc MNOHEM obsáhlejší a je opraveno i mnoho chyb, takže doporučuji tento tutoriál pročíst celý, i když máte za sebou původní verzi. Pokud byste z jekéhokoli důvodu původní verzi sháněli, najdete ji tady.

Odkazy jsou psány tmavě červeně, označené odkazy červeně a podtrženě. Zdrojový kód bude psán tmavomodře. Názvy souborů nebo jiné důležité věci budou podtrženy, popřípadě zvýrazněny.

Nebudu se tady sáhodlouze rozepisovat o nějakých autorských právech - klidně si cokoli jakkoli změňte, když vám to pomůže. Jenom by mě docela nakrklo, kdyby někdo nahradil moje jméno svým a tohle prodával. Ale to se doufám stejně nestane (koneckonců, kdo by si to koupil, že :))

Ať už mi budete chtít sdělit cokoliv, pište mi na mail jezuro@post.cz.
Tak se pohodlně usaďte, lekce začíná...

FAQ (Frequently Asked Questions) - Často kladené otázky

Co je to sakra ten dialog?
1) Rozhovor dvou osob
2) Typ rozhraní v programech
-hádejte, o které možnosti se budeme bavit...
Možná vás to překvapí, ale CELÝ interface (tedy uživatelské rozhraní) Operace Flashpoint jsou dialogy. Dialogem může být takřka cokoliv - od nenápadé černé čárky až po tabulku pro vkládání jednotek v editoru. Ano, celý editor misí je také "jenom" soustava různých dialogových oken!

Nějaký okna - na co mi to bude?
Tuhle otázku jsem sám sobě taky položil. A sám si taky dal odpověď - bohužel tu klasickou (na ho*no, abych byl slušný.) To mě na nějakou dobu od této tématiky odradilo, ale když se mi dostal do rukou OFP EdiorHelp a ukázková mise k tématu dialogů, uvědomil jsem si, že tohle nemůžu jen tak přejít.
Pomocí dialogů můžete v OFP udělat v podstatě jakékoli okno, od černého čtverečku v pravém dolním rohu monitoru po velící panel koordinovaného útoku několika skupin spojený s rozkazy jednotlivým vojákům. Možností je nepřeberné množství a já vám v tomto tutoriálu ukážu základy, na nichž můžete vybudovat sebesložitější dialog.

Tak jo - co k tomu budu potřebovat?
Pro základní dialogy stačí jenom klasický soubor Description.ext. Dále můžete přidat obrázky a samozřejmě skritpy, soubory Stringtable.csv nebo funkce s příponou .sqf. Soubor Description.ext může být umístěn buď ve složce s misí (tam ho program hledá nejdřív) nebo v hlavní složce kampaně (když ho v misi nenajde, hledá tam.) A když není ani tady, podívá se do souboru Resource.bin ve složce OFP\Res\Bin, popřípadě OFP\BIN.

Je těžký se to naučit?
Je a není. Pokud máte chuť a trpělivost se s dialogy naučit pracovat, půjde to (skoro) samo ;)

Ukázka definice

Na této stránce najdete obrázky a definice všech objektů, které se mi podařilo v OFP vykoumat. Je to užitečné, ale jednotlivé objekty samy o sobě moc neznamenají. Důležité je i jejich uspořádání a funkce. Abyste měli lepší představu běžného dialogového okna, obrázek jednoho vzorového sem šoupnu (podotýkám, že v něm nejsou použity všechny objekty vyjmenované výše.)

Abychom to měli pěkně pohromadě, tady je zdrojový kód k tomuto dialogovému oknu. Hned potom si ho podrobně projdeme. Dále si můžete stáhnout ukázkovou misi - je v ní nadefinován dialog z obrázku výše. Misi zkopírujte do složky Flashpoint\Users\Jméno\missions. No a teď se vrhneme na vysvětlování toho kódu.

Popis definice

Určitě nebude od věci si vysvětlit, co jednotlivé "značky" v definici dialogu znamenají. Čísla před názvy si vysvětlíme později.

Typy objektů - určuje, jak se bude objekt chovat.
0 (CT_STATIC) : Do této kategorie patří objekty, se kterými uživatel nemuže nic dělat - prostě tam jen jsou. Spadají sem například obrázky, titulní rámečky, pozadí okna, texty a další neinteraktivní objekty.
1 (CT_BUTTON) : Tlačítka. Když je zmáčknete, ozve se ťuknutí a provede nějaká akce. O tom později.
2 (CT_EDIT) : Kolonka na text, do které může uživatel sám něco vepsat a potom to třeba zkopírovat. Tohoto typu je třeba v editoru misí kolonka "Při aktivaci" ve spínačích.
3 (CT_SLIDER) : Jezdec. Když uživatel ťukne na šipku a drží ji, může s ní jezdit po stupnici. Jezec je třeba "Pravděpodobnost výskytu" při vkládání jednotek v editoru.
4 (CT_COMBO) : Vysunovací nabídka, "roletka". Při kliknutí na rámeček se nabídka rozbalí a vy si můžete vybrat z různých položek v ní. Při dalším kliknutí se nabídka zavře a v rámečku zůstane vámi vybraná položka. Použito třeba při výběru hudby ve spínačích.
5 (CT_LISTBOX) : Další nabídka, tentokrát ale pevná - nevysunovací. Je použita například v obrazovce výběru ostrovů editoru misí.

Styly objektů - zarovnání - určuje, jak bude objekt zarovnán.
0 (ST_LEFT) : Běžné zarovnání - vlevo.
1 (ST_RIGHT) : Zarovnání vpravo.
2 (ST_CENTER) : Zarovnání doprostřed.
3 (ST_UP) : Text začíná na horní straně vyhrazeného prostoru.
4 (ST_DOWN) : Text začíná na dolní straně vyznačeného prostoru.
5 (ST_VCENTER) : Tohle mi nějak nefungovalo, možná to má text nějak otáčet (?)

Styly objektů - vzhled - určuje, jak bude objekt vypadat.
0 (ST_SINGLE) : Text, který je takto vypsán, může být napsán jen na jeden řádek.
16 (ST_MULTI) : Text, který je takto vypsán, může být napsán na více řádků.
32 (ST_TITLE) : Rámeček pro nadpis dialogového okna.
48 (ST_PICTURE) : Obrázek.
80 (ST_3D_BORDER) : "Oblemování" - 3D okraj s pozadím dialogového okna.
96 (ST_NO_BORDER) : Bez rámečku.
128 (ST_HUD_BACKGROUND) : Poloprůhledné pozadí.
160 (ST_WITH_RECT) : Okolo objektu (např. textu) bude vykreslen rámeček.
256 (ST_SHADOW) : Objekt má stín.
512 (ST_NO_RECT) : Objekt (např. text) není ohraničen rámečkem.

Parametry - upřesňují podrobné vlastnosti dialogů.
IDD : Identifikační číslo dialogu. Každý dialog musí mít svoje vlastní IDD - na toto číslo se odkazují různé příkazy. Za IDD si můžete dát libovolné číslo, doporučuji ale začít zažitou tisícovkou.
MovingEnable : Nevím, co to dělá - při změně čísla nezaznamenáte změnu. Tak tam nechte tu jedničku...
IDC : V podstatě to samé jako IDD, jen je to identifikátor jednotlivých objektů.
type : Viz Typy objektů.
style : Viz Styly objektů - zarovnání a vzhled.
x : Vzdálenost levého horního rohu objektu od levé strany monitoru.
y : Vzdálenost horní strany objektu od horní strany monitoru.
w : Šířka objektu.
h : Výška objektu.
text : Text, který bude vepsán v objektu (u RscText to bude samozřejmě ten text :)), např. popis tlačítka. U RscPicture je to název obrázku.
font : Font písma použitý pro text. Zde je přehled těchto fontů:

SizeEx : Relativní velikost písma vůči monitoru - například pro písmo o výšce dvacetiny obrazovky bude SizeEx = 0.05;.
size : Absolutní velikost písma - "size = 1;" znamená defaultní (základní) velikost fontu, "size = 1.5;" je o 50% větší než základní atd.
ColorBackground[] : Barva pozadí ve formátu RGB + I (Red, Green, Blue, Intensity) - červená, zelená, modrá, intenzita. Když chcete udělat poloprůhledné pozadí, zadáte za intenzitu 0.5. Defaultní intenzita je 1 - neprůhledná.
ColorText[] : To samé, jako ColorBackground[], ale vztahuje se na barvu písma.
color[] : Barva písma objektu (např. tlačítka), formát stejný jako u předchozích dvou.
LineSpacing : Řádkování. "LineSpacing = 1;" je standardní řádkování, "LineSpacing = 1.5;" udělá mezeru mezi řádky o 50% vyšší atd.
default : Používá se u tlačítek. Když je hodnota zadána na 1, je tlačítko označeno už při spuštění dialogu a po stisku klávesy Enter se sepne. Pří hodnotě 0 musíte na tlačítko ťuknout myší.
SoundPush[] : Zvuk, který tlačítko vydá, když na něj ťuknete. První parametr je název zvuku a cesta k němu, druhý je hlasitost (1.0 znamená běžnou hlasitost, ale používá se 0.2) a třetí udává rychlost, jakou je zvuk přehráván (standartně 1.0.)
SoundClick[] : U tohoto si nejsem úplně jist. Jak můžete vidět v příkladu, při této události se žádný zvuk nepřehraje.
SoundEscape[] : Tak tady si taky nejsem jist :(. Ten zvuk se občas přehraje - můžete ho slyšet, ale nevím přesně kdy.
WholeHeight : Maximální výška rozbaleného ComboBoxu. Pokud se do této výšky všechny položky nevejdou, bude na pravé straně jezdec, kterým můžete výběr posouvat.
ColorSelect[] : Barva písma vybrané položky ComboBoxu.
AutoComplete : Sem můžete dosadit "Scripting" - Potom se bude nad vepisovaným textem objevovat nabídka editačních příkazů. Jinak můžete nechat prázdné, tedy AutoComplete = "";.
action : Příkaz, který se vykoná po stisknutí tlačítka nebo aktivního textu.
RowHeight : Tento příkaz mi fungoval jen u ListBoxů. Když nastavíte RowHeight = 0, budou jednotlivé řádky, tedy položky v ListBoxu vysoké přesně podle velikosti svého písma. Když budete hodnotu zvyšovat, budou od sebe jednotlivé položky dál a dál.

Jak vidíte, definice dialogu je v podstatě úplně něco jiného, než s čím jsme se mohli doposud setkat. Některé obecné zásady jsou ale stejné. Tak si je tady uvedeme nejdřív.

Konečně samotný zdroj :
Na začátku zdrojového kódu jsou definovány typy a styly objektů, neboli výměna čísel za srozumitelnější slova - tady vlastní pojmenování smysl rozhodně má, protože se třeba ST_PICTURE asi pamatuje lépe než číslo 48. Nejsou zde uvedeny všechny, ale jen ty, které se běžně používají.
Co to vlastně definice je? V tomto případě je to přiřazení vlastního názvu předem jinak definovaného typu nebo stylu. Vlastně takové "přejmenování".

Potom následuje předdefinování, "nachystání" jednotlivých tříd. Každý objekt v dialogu musí mít definované všechny svoje atributy neboli vlastnosti. Toto předdefinování vás ušetří toho, abyste museli při každém začlenění nějakého objektu do dialogu vždycky definovat všechny jeho vlastnosti. Takhle si můžete předem připravit ty hodnoty, které budete měnit jen velmi zřídka nebo vůbec.

A konečně poslední část přípravy dialogu - samotné umísťování objektů. O tom se podrobněji rozepíšu níže, protože to mnoha lidem dělá problémy.

Úpravy kódu a vzhledu dialogů

Psaní kódu :
U kódů v Operaci Flashpoint je úplně jedno, jestli budete psát všechna písmena malá, VELKÁ, nebo třeba rOzHáZeNá. Jak ale vidíte, ne všechny styly psaní jsou přehledné. Těm, co mají nějaké zkušenosti s programovacími jazyky (obzvláště C nebo C++), bude asi nejvíc vyhovovat psaní příkazů stylem "první písmeno prvního slova malé, první písmena ostatních slov velká (např. colorBackground[].) Většina (nebo alespoň mnoho) příkazů v OFP je totiž tvořeno složením více slov. Já píšu stylem "první písmena všech slov velká, pokud je příkaz pouze jednoslovný, na začátku malé (aby se mi to nepletlo s názvy proměnných nebo objektů, např. ColorBackground[])". Jak jsem ale řekl, je to jenom na vás...
Asi jste si všimli i toho, že se jinak píšou i poznámky. V souboru Description.ext se k tomuto účelu používají dvě lomítka ("//".) Poznámku můžete vložit i za konec kódu v řádku.
Jako vždy, i zde platí, že název třídy nebo jakékoli jiné uživatelem pojmenované části dialogu nesmí obsahovat mezery ani diakritiku (tedy abych byl přesný, skriptovací jazyk OFP některé diakritické znaky, například "á", bere, ale většinu ne, takže pro jistotu diakritiku prostě nepoužívejte.)

Formátování kódu :
Stejně jako u velikosti písmen, i u formátování zdrojového kódu je vše jenom na vás. Mezi jednotlivými příkazy si můžete vložit kolik mezer chcete. Co ale určitě doporučuji, je používat tabulátor k rozdělení vnořených tříd. Když se vám třeba stane, že někde zapomenete ukončovací středník, bude pro vás daleko jednodušší najít kde. Doporučuji použít další tabulátor vždy, když otevřete nějakou další třídu levou složenou závorkou ("{") Tady se můžete podívat na rozdíl mezi formátovaným a neformátovaným kódem:
// FORMÁTOVANÝ KÓD

class RscTest
{
	IDD = 1000;
	MovingEnable = 1;

	class Controls
	{
		class Background : RscBackground
		{
			x = 0.250000;
			y = 0.250000;
			w = 0.500000;
			h = 0.500000;
		};
		
		class SubBackground : RscGroupBox
		{
			x = 0.270000;
			y = 0.270000;
			w = 0.460000;
			h = 0.460000;
		};
	};
};

// NEFORMÁTOVANÝ KÓD

class RscTest
{
IDD=1000;
MovingEnable=1;
class Controls
{
class Background:RscBackground
{
x=0.250000;
y=0.250000;
w=0.500000;
h=0.500000;
};
class SubBackground:RscGroupBox
{
x=0.270000;
y=0.270000;
w=0.460000;
h=0.460000;
};
};
};
Tohle byl jenom krátky vyňatek, běžný kód bývá asi 20x delší :)

Umisťování objektů a jejich zarovnávání :
Nevím, jak ostatním, ale mně dělalo ze začátku největší problémy pochopit, jak správně nastavit x, y, w a h tak, aby objekty "seděly" tak, jak jsem potřeboval - buď byly moc dlouhé, moc vlevo, moc nahoře a ještě větší problémy nastaly, když jsem nastavil zarovnávání na střed. To mě přimělo se o této záležitosti trochu víc rozepsat.

Zarovnáváním se nebudete zabývat jen u textu. Zdaleka ne. Souřadnice si budete pravděpodobně počítat na papír pro všechny objekty (pozadí, obrázky, slidery, tlačítka, ...), kreslit si, jak bude dialogové okno vypadat a upravovat velikosti objektů tak, aby se vám to tam všechno vlezlo (alespoň já to tak dělám...) Nejlepší pro správné pochopení bude, když si rozebereme pár vzorových příkladů (zdrojový kód nebudu vypisovat celý, ale jen hodnoty používané pro umísťování objektů - x, y, w a h.) Ještě přidám obrázek, abyste si význam těchto hodnot lépe představili:

Myslím, že v tom už máte jasno ;) A teď ty příklady:

1) Objekt široký půlku obrazovky a vysoký čtvrtinu obrazovky. Umístěn má být doprostřed:
x = 0.250000;
y = 0.350000;
w = 0.500000;
h = 0.250000;
2) Objekt přes úplně celou obrazovku:
x = 0.000000;
y = 0.000000;
w = 1.000000;
h = 1.000000;
3) Objekt ve tvaru čtverce, jehož strana je dlouhá čtvrtinu šířky obrazovky, umístěný doprostřed obrazovky:
x = 0.500000;
y = 0.333333;
w = 0.250000;
h = 0.333333;
Je důležité si uvědomit, že velikosti objektů jsou zadávány v poměru vůči monitoru. To je dobře vidět na posledním příkladu. Chcete-li, aby byl objekt čtverec s délkou strany rovnou čtvrtině šířky obrazovky (při rozlišení 1024x768 to bude 256 pixelů), musí mít hodnotu y jednu třetinu (0.333333) Poměr stran monitoru je totiž 4:3 (1024:768 je po zkrácení 4:3.)
"Objektem" můžeme nazvat jakoukoliv část dialogu, ať už jde o text, tlačítko, obrázek atd. U většiny objektů je postup zarovnávání jasný, ale jsou tu i některé "špeky". Tady je několik příkladů:

Text: Je jedno, jestli text zarovnáváte doleva, na střed nebo doprava. Vždy mu pouze nastavíte prostor, který nesmí přesáhnout. Když je zarovnán doleva, bude začínat vlevo, když doporostřed, bude začínat uprostřed atd. Když se celý text do vámi nadefinovaného prostoru nevejde, bude "useknutý".
Obrázek: Vždycky se deformuje do požadovaných rozměrů. Pozor si na to dejte obzvlášť při rovnostranných obrázcích, viz. příklad výše.
Pozadí, tlačítka, ...: Tady je to snad nejjasnější. Prostě to bude velké přesně jako zadaný protor. Platí i pro veškeré ostatní objekty obdélníkového tvaru.
Slidery: Je třeba si dát pozor a dobře rozlišovat horizontální (vodorovné) a vertikální (svilsé) slidery. V prvním případě bude větší hodnota w, tedy šířka a ve druhém logicky h - výška.
Aktivní text: Zarovnává se stejně jako normální text, ale je tu jedno úskalí. Jak můžete vidět na obrázku v seznamu objektů, je tento text vždy podtržený. Ale ta podtrhovací linka se nevytvoří automaticky těsně pod textem (což by bylo logické), ale na spodní straně prostoru vymezeného pro aktivní text. Divný, co? Proto je třeba odzkoušet, jak je text vysoký.

Obecně si stačí uvědomit, jak velkou část obrazovky objekt zabere. Řeknete si třeba, že uděláte tři stejně velká tlačítka vedle sebe se stejnými mezerami mezi sebou, třeba 0.05. A navíc to celé chcete mít pěkně uprostřed obrazovky. Velice jednoduché ;) Jako vzorové tlačítko nám poslouží to z ukázkové definice. To má šířku (w) 0.1 a výšku (h) 0.035.
Začneme vypočítáním hodnoty x prvního tlačítka. Pamatujte, že tlačítka budou tři, takže šířku jednoho tlačítka vynásobíme třemi. Do toho ale musíme započítat dvě mezery (mezi prvním a druhým a mezi druhým a třetím). Tím dostaneme šířku obrazovky, kterou nám budou tlačítka zabírat:
3 x 0.1 = 0.3
2 x 0.05 = 0.1
---------------------
0.3 + 0.1 = 0.4
Tři tlačítka nám tedy budou zabírat 0.4 obrazovky. Budou uprostřed, takže napravo i nalevo nám zbude 0.3 obrazovky ((1 - 0.4) / 2 = 0.3.) Hodnota x prvního tlačítka tedy bude 0.3.
Teď hodnoty x ostatních tlačítek: k tomu 0.3 musíme přičíst šířku tlačítka i mezeru:
0.3 + 0.1 + 0.05 = 0.45
Hodnota x druhého tlačítka bude 0.45. Stejným postupem pokračujeme i u třetího tlačítka:
0.45 + 0.1 + 0.05 = 0.6
Nezapomeňte, že to teď počítáme podle druhého tlačítka - třetí tlačítko bude mít x rovno 0.6.
Hodnota y bude pro všechna tlačítka stejná, protože jsou ve stejné výšce. tlačítka jsou vysoká 0.035 obrazovky. Vypočítání y je hračka:
(1 - 0.035) / 2 = 0.4825
Takže vlastně odečteme výšku tlačítka od celkové výšky monitoru (1) a potom vydělíme dvěma, abychom dostali jenom vzdálenost od horní strany obrazovky k horní straně tlačítka. Pro všechny tlačítka bude hodnota y 0.4825.


Tak. Všechno, co jsme potřebovali spočítat, máme. Já vím, že to takhle rozsáhle vysvětlený může vypadat překomplikovaně, ale když se na to pořádně podíváte, zjistíte, že na tom nic není.
Tady je kompletní soubor Description.ext k těmto třem tlačítkům. Při klepání na ně se objeví různé hinty - můžete si Description zkopírovat do mise a vyzkoušet to.

Závěr

Tak a je tu konec. Doufám, že vám tenhle tutoriál aspoň trochu pomohl a vaše hranice v editaci misí se zase posunuly o kus dál. Ještě jsem chtěl přidat výčet a popis skriptiovacích příkazů týkajících se dialogů, ale ty má Ruprt všechny dobře vysvětlené v jeho OFP EditorHelpu, který stejně všichni máme. Jestli něčemu nerozumíte, neváhejte a mailujte jako o život.

                                                           

Ježuro (člen skupiny 2DMM Team), 2004