| 
             
            Tutorial 
            28 - Práce s dialogy  | 
           
          
            | 
             
            Autor
              : Ruprt  | 
           
          
            | 
            
            Download = Tento tutorial + ukázka | 
           
         
        
       
        
        
      
      Co je to vlastně 
      dialog ? 
      Dialog je všem uživatelům PC dobře znám i přesto, že kolikrát vlastně ani 
      nevědí, že se o dialogové okno právě jedná. Dialogem jsou veškerá okna 
      aplikací sloužící k tomu, aby uživateli podaly nějakou zprávu nebo 
      informaci, nebo aby od uživatele daná aplikace získala nějaká data nebo 
      rozhodnutí. Typickým dialogovým oknem je například okno požadující po 
      uživateli zadání jména a hesla při spouštění operačního systému Windows, 
      nebo okénko zobrazené po provedení změny v souboru např. u aplikace MS 
      Word dotazující se uživatele, zda-li mají být provedené změny uloženy. U 
      OFP je typickým dialogovým oknem celý Editor misí nebo okénko spouštěné 
      pomocí příkazu HintC. Když se to vezme kolem a kolem OFP celé je vlastně 
      založeno na dialogových oknech -> brífingovým zápisníkem počínaje (zkuste 
      si jen tak pro zajímavost jednou napsat do pole PŘI AKTIVACI jakéhokoli 
      spínače vysílačky toto : check = CreateDialog "RscDisplayMainMap", a pak 
      ji spusťte) a zobrazením cinemaborderu při zabití hráče konče (check = 
      CreateDialog "RscDisplayMissionEnd"). 
       
       
      K čemu v OFP potřebujeme dialogy ? 
      Dialog je velmi silný nástroj pomáhající tvůrci misí vytvářet mise mnohem 
      zajímavější, větvené, poskytující hráči možnosti volby, jak se bude hra 
      dále vyvíjet v závislosti na jeho rozhodnutí. Takto je jednoduše možné dát 
      hráči na výběr tím, že v určité fázi hry se mu objeví dialogové okno, 
      které mu nabídne např. takovéto možnosti : 1) bude pokračovat dál, sám a s 
      větším rizikem, 2) Přivolá na pomoc další vojáky, 3) Úkol ležící před ním 
      vynechá a bude pokračovat dál aniž by daný úkol splnil (a mise by dál 
      nemohla pokračovat), nebo 4) Misi prostě ukončí, přičemž každá z těchto 
      voleb bude nějak bodově ohodnocena (toto se jeví aplikovatelné především u 
      kampaní) a podle dosaženého počtu bodů se bude kampaň dále vyvíjet. 
      V neposlední řadě může být dialogové okno velmi silným pomocníkem tvůrce 
      při samotném vývoji a testování mise. Kdokoli si již alespoň jednou zkusil 
      misi vytvořit, bude se mnou souhlasit, že by práce byla mnohem jednodušší, 
      kdyby při při testovacím běhu mise věděl, na jakých souřadnicích se např. 
      určitá jednotka nachází, jak daleko je nejbližší nepřítel, jakou zbraň 
      právě používá raketometčík, který má odpálit BVPéčko (obvykle má zrovna v 
      ruce jenom klacek) a kde se (ksakru) zrovna nachází podpůrná skupina. Tak 
      tohle všechno lze jednoduše zjistit pomocí jednoho předem definovaného 
      dialogového debug okna, které si spustíte např. nabídkou v akčním menu 
      nebo prostě vysílačkou. 
       
  
      
      Popis logiky 
      definice tříd dialogů - description.ext 
      Základem jakéhokoli dialogového okna je definice jeho tříd (class), které 
      OFP vyhledává v souborech v pořadí : 
      1) description.ext - v adresáři mise 
      2) description.ext - v adresáři kampaně 
      3) resource.bin - v vdresáři \Res\Bin nebo\Bin hry OFP 
       
      Tyto třídy jsou vlastně stavební kameny jednotlivých prvků (objektů) 
      dialogu jako jsou např. tlačítka, rámečky, texty, obrázky, comboboxy apod. 
      (pozn. skládají se z vlastností, metod a funkcí - ale to není důležité 
      vědět. Pokud však máte nějaké zkušenosti s některými programovacími jazyky 
      jako jsou např. VisulaBasic, C++, Visual FoxPro, budete mít práci s 
      pochopením tříd velmi usnadněnou). 
       
  
      
      Příklad vytvoření 
      dialogu 
      Pro základní pochopení tvorby dialogu zde popíšu postup vytvoření a 
      spuštění velmi oblíbeného okna začátečníků ve všech programovacích 
      jazycích "Hello, World!", které doplním o combobox a funkci získání a 
      zobrazení souřadnic jednotlivých vojáků ve skupině hráče. Misi provedeme 
      ve dvojjazyčném zpracování. 
      Misi si umístíme na ostrov Desert Island (nejrychleji se načítá). Kamkoli 
      (na pevninu :o)) si umístíme skupinu vojáků Západu a hráče uděláme 
      velitelem. Poté si misi uložíme jako HelloWorld. 
      V adresáři HelloWorld, který nám hra sama vytvořila, najdeme pouze soubor 
      mission.sqm. V tomto adresáři vytvoříme soubor description.ext 
      (upozornění: pokaždé, když upravíte soubor desription.ext nebo stringtable.csv, 
      je nutné misi znovu načíst aby se změny projevily) do kterého vepíšeme 
      následující kód: 
       
  
        
          
            | 
            #define 
            FontMAINCZ | 
            
            
            "SteelfishB64CE" | 
            
            // definice typu písma | 
           
          
            | 
            #define 
            FontNOTES  | 
            
            
            "AudreysHandI48" | 
            
            // definice typu písma | 
           
          
            | 
            #define 
            FontS | 
            
            
            "tahomaB24" | 
            
            // definice typu písma | 
           
          
            | 
            #define 
            FontM | 
            
            
            "tahomaB36" | 
            
            // definice typu písma | 
           
          
             | 
             | 
            
             | 
           
          
            | 
            // Control 
            types | 
             | 
            
             | 
           
          
            | 
            #define CT_STATIC
             | 
            
            0 | 
            
            // statický typ (text, pozadí, obrázek apod.) | 
           
          
            | 
            #define CT_BUTTON | 
            
            1 | 
            
            // Tlačítka | 
           
          
            | 
            #define CT_COMBO | 
            
            4 | 
            
            // ComboBoxy | 
           
          
             | 
             | 
            
             | 
           
          
            | 
            // Static 
            styles | 
             | 
            
             | 
           
          
            | 
            #define 
            ST_LEFT | 
            
            0 | 
            
            // zarovnání textu doleva | 
           
          
            | 
            #define 
            ST_RIGHT | 
            
            1 | 
            
            // zarovnání textu doprava | 
           
          
            | 
            #define 
            ST_CENTER | 
            
            2 | 
            
            // zarovnání textu na střed | 
           
          
            | 
            #define 
            ST_UP | 
            
            3 | 
            
            // zarovnání textu nahoru | 
           
          
            | 
            #define 
            ST_DOWN  | 
            
            4 | 
            
            // zarovnání textu dolu | 
           
          
            | 
            #define ST_VCENTER  | 
            
            5 | 
            
            // zarovnání textu vertikálně - otočí 
            text o 90° po směru hodinových ručiček | 
           
          
             | 
             | 
            
             | 
           
          
            | 
            #define ST_SINGLE | 
            
            0 | 
            
            // do pole lze zadat pouze 1 řádek textu 
            - nelze použít \n pro přechod na další řádek | 
           
          
            | 
            #define ST_MULTI | 
            
            16 | 
            
            // do pole lze zapsat více řádek textu - 
            lze použít \n pro přechod na další řádek | 
           
          
            | 
            #define ST_TITLE | 
            
            32 | 
            
            // titulkový rámeček | 
           
          
            | 
            #define ST_PICTURE | 
            
            48 | 
            
            // obrázek | 
           
          
            | 
            #define 
            ST_3D_BORDER | 
            
            80 | 
            
            // rámeček je vyplněn a má 3D okraj | 
           
          
            | 
            #define ST_NO_BORDER | 
            
            96 | 
            
            // rámeček bez okraje | 
           
          
             | 
             | 
            
             | 
           
          
            | 
            #define 
            ST_HUD_BACKGROUND | 
            
            128 | 
            
            // typ podkladu - je průsvitný | 
           
          
            | 
            #define 
            ST_WITH_RECT | 
            
            160 | 
            
            // rámeček bude mít viditelný okraj | 
           
          
            | 
            #define 
            ST_SHADOW | 
            
            256 | 
            
            // písmo bude mít stín | 
           
          
            | 
            #define 
            ST_NO_RECT | 
            
            512 | 
            
            // rámeček nebude mít viditelný okraj | 
           
         
      
        
       
      (toto není tak moc důležité neboť se tím pouze přiřadily lépe 
      zapamatovatelné názvy typům a stylům objektů - důležitá jsou čísla a ta 
      jsou již předem nadefinována. Jinými slovy kód by fungoval i bez výše 
      uvedeného, ale musely by se používat pouze čísla a ta se hůře pamatují) 
       
      Nyní si nadefinujeme základní třídy objektů dialogu (base control classes). 
      Opět to není nutné, ale práce se tím podstatně zjednodušuje, neboť bez 
      základních tříd by se musely všechny objekty definovat zvlášť, což zabírá 
      moc času a mnohem víc řádek kódu. Takto vždy každý objekt odvodíme od již 
      definované základní třídy. Takže : 
       
      class RscBackground 
      { 
      type=CT_STATIC 
      idc=-1 
      style=ST_3D_BORDER 
      x=0.150000; 
      y=0.150000; 
      w=0.700000; 
      h=0.700000; 
      text=""; 
      colorBackground[]={1,1,1,1}; 
      colorText[]={0,0,0,0}; 
      font="tahomaB24"; 
      sizeEx=0 
      }; 
       
      class RscTitle 
      { 
      type=CT_STATIC 
      idc=-1 
      style=ST_TITLE + ST_CENTER; 
      x=0.150000; 
      y=0.164000; 
      w=0.700000; 
      h=0.060000; 
      text=""; 
      colorBackground[]={1,1,0,1}; 
      colorText[]={1,1,1,1}; 
      font="tahomaB36"; 
      sizeEx="1.0714 * 0.03"; 
      }; 
       
      class RscGroupBox 
      { 
      type=CT_STATIC 
      idc=-1 
      style=ST_NO_BORDER 
      text=""; 
      colorBackground[]={0,0,0,0}; 
      colorText[]={0,0,0,0}; 
      font="tahomaB24"; 
      sizeEx=0.020000; 
      }; 
       
      class RscText 
      { 
      type=CT_STATIC 
      idc=-1 
      style=ST_LEFT + ST_MULTI + ST_NO_RECT; 
      lineSpacing=1.000000; 
      h=0.040000; 
      colorBackground[]={0,0,0,0}; 
      colorText[]={0.080000,0.080000,0.120000,0.750000}; 
      font="tahomaB24"; 
      sizeEx=0.020000; 
      }; 
       
      class RscPicture 
      { 
      type=CT_STATIC 
      idc=-1 
      style=ST_PICTURE 
      colorBackground[]={0,0,0,0}; 
      colorText[]={1,1,1,1}; 
      font="tahomaB24"; 
      sizeEx=0 
      }; 
       
      class RscButton 
      { 
      type=CT_BUTTON 
      style=ST_CENTER 
      w=0.110000; 
      h=0.050000; 
      colorText[]={0.080000,0.080000,0.120000,1}; 
      font="tahomaB24"; 
      sizeEx=0.020000; 
      default=0 
      soundPush[]={"ui\ui_ok",0.200000,1}; 
      soundClick[]={"",0.200000,1}; 
      soundEscape[]={"ui\ui_cc",0.200000,1}; 
      }; 
       
      class RscCombo 
      { 
      type=CT_COMBO 
      style=ST_LEFT 
      h=0.040000; 
      wholeHeight=0.250000; 
      colorSelect[]={0.350000,0.380000,0.360000,1}; 
      colorText[]={0.080000,0.080000,0.120000,0.750000}; 
      colorBackground[]={0.350000,0.380000,0.360000,0.750000}; 
      font="tahomaB24"; 
      sizeEx=0.020000; 
      }; 
       
      Vysvětlivky : 
      idc - index třídy objektu (vlastně takový číselný název), zde většinou -1, 
      neboť se jedná o base class 
      style - chování objektu (zarovnání apod.) 
      colorBackground - barva pozadí RGBA (1 = 255 = FF (HEX) a 0 = 0 = 00(HEX)) 
      - A je průsvitnost 
      colorText - barva písma RGBA (1 = 255 = FF (HEX) a 0 = 0 = 00(HEX)) - A je 
      průsvitnost 
      colorSelect - barva podkladu myší vybrané položky ComboBoxu - RGBA 
      font - typ písma (lze použít i ony definice např. FontMAINCZ, ale tady je 
      lepší používat název písma) 
      lineSpacing - velikost mezery mezi řádky při stylu ST_MULTI 
      sizeEx - velikost písma 
      size - velikost písma 
      default - standardní/hlavní tlačítko (když se stiskne ENTER stiskne se 
      tlačítko s default=1) 
      soundPush/Escape/Click - zvuk, který se přehraje při stisku tlačítka OK/Cancel/ostatní 
      x - vzdálenost levého horního rohu objektu od levého okraje obrazovky, 
      0-úplně vlevo, 1-úplně vpravo 
      y - vzdálenost levého horního rohu objektu od horního okraje obrazovky, 
      0-úplně nahoře, 1-úplně dole 
      w - šířka objektu 
      h - výška objektu 
      wholeHeight - výška rozbaleného ComboBoxu 
       
      No a teď když máme definovány základní třídy objektů, můžeme se vrhnout na 
      samotnou tvorbu dialogového okna : 
       
      class RscHelloWorld 
      { 
      idd=1000 
      movingEnable=1 
      class Controls 
      { 
       
      // ---------------------------------------- 
      // --------- Dialog Appearence ------------ 
      // ---------------------------------------- 
       
      class Background: RscBackground //vytvoří základní rámeček celého dialogu 
      { 
      x=0.250000; 
      y=0.250000; 
      w=0.500000; 
      h=0.500000; 
      }; 
      class SubBackground: RscGroupBox // vytvoří druhý rámeček uvnitř základníh, 
      čímž se zvýrazní 
      { 
      x=0.270000; 
      y=0.270000; 
      w=0.460000; 
      h=0.460000; 
      }; 
       
      // ---------------------------------------- 
      // -------------- TextBoxes --------------- 
      // ---------------------------------------- 
       
       
      class Title: RscTitle //Rámeček titulku dialogu s nadpisem "Hello, World 
      !" 
      { 
      idc=1001 
      x=0.350000; 
      y=0.270000; 
      w=0.300000; 
      h=0.060000; 
      text="$STR_DLG_Title"; 
      }; 
       
      class TextBox1: RscTitle //Rámeček pro výpis textů  
      { 
      idc=1002 
      x=0.290000; 
      y=0.350000; 
      w=0.420000; 
      h=0.180000; 
      text=""; 
      sizeEx="0.022"; 
      }; 
      class TextBox2: RscText //Textové pole pro výpis textů uvnitř 1.rámečku 
      { 
      idc=1003 
      x=0.300000; 
      y=0.360000; 
      w=0.400000; 
      h=0.160000; 
      colorBackground[]={0,0,0,0}; 
      colorText[]={1,1,0,1}; 
      text="$STR_TextBox2_1"; 
      sizeEx="0.024"; 
      }; 
       
       
      // ---------------------------------------- 
      // -------------- Buttons ----------------- 
      // ---------------------------------------- 
       
      class GetData: RscButton // Tlačítko "Získej údaje" 
      { 
      idc=2001; 
      x=0.580000; 
      y=0.550000; 
      text=$STR_BTN_GetData; 
      action="Player Exec ""onClickGetData.sqs"""; 
      }; 
       
      class ButtonCancel: RscButton //Tlačítko "Cancel" 
      { 
      idc=2002 
      x=0.385000; 
      y=0.640000; 
      w=0.130000; 
      h=0.050000; 
      text="$STR_BTN_CANCEL"; 
      action="CloseDialog 1000; sd = Nil"; 
      }; 
      // ---------------------------------------- 
      // -------------- ComboBoxes -------------- 
      // ---------------------------------------- 
       
      class CBSoldiers: RscCombo //Vytvoří ComboBox 
      { 
      idc=3001 
      style = ST_TITLE + ST_CENTER; 
      x=0.315000; 
      y=0.565000; 
      w=0.250000; 
      h=0.025000; 
      colorSelect[]={1,1,1,1}; 
      colorText[]={0,0,0,0.750000}; 
      rowHeight=0.025000; 
      }; 
       
      // ---------------------------------------- 
      // --------------- Pictures --------------- 
      // ---------------------------------------- 
       
      class RuprtLogo: RscPicture //Umístí do dialogu obrazek 
      { 
      idc=4001 
      text="ruprtslogo.jpg"; 
      x=0.581900; 
      y=0.610000; 
      w=0.107500; 
      h=0.115000; 
      colorText[]={1,1,1,1}; 
      }; 
      }; 
      }; 
       
      A toť vše. 
      Údaj Action u tlačítek je vlastně metoda, která se spustí při stisku 
      daného tlačítka a provede veškeré příkazy uvedené v uvozovkách za 
      rovnítkem. Příkazů může být několik, musí však být odděleny středníkem. 
      Nastavení této metody lze za běhu programu změnit příkazem ButtonSetAction. 
       
      Teď je nutné si vytvořit soubor stringtable.csv, aby mohly být získávány 
      texty pro všechny objekty dialogu a do tohoto souboru zapsat následující : 
       
      Language, Czech, English, Comment 
       
      STR_DLG_Title, "Hello, World !", "Hello, World !", 
       
      STR_TextBox2_1, "\nVyberte z ComboBoxu níže vojáka, jehož\n\nsouřadnice se 
      vám zobrazí v tomto rámečku.", "\nChoose a soldier from ComboBox bellow\n\nto 
      display his coordinates.", 
      STR_TextBox2_2, "Voják ""%1"" je na souřadnicích :\nOsa X = %2\nOsa Y = 
      %3\nOsa Z = %4\núhel = %5°\nnázev jednotky = %6", "Soldier ""%1"" is on 
      coordinates :\nX axis = %2\nY axis = %3\nZ axis = %4\nangle = %5°\nname of 
      unit = %6", 
       
      STR_BTN_GetData, Získej údaje, Get Data, 
      STR_BTN_CANCEL, Ukončit, Cancel, 
       
      STR_CB_Txt_0, Vyberte vojáka, Choose a soldier, 
      STR_AddAction_0, Spustit dialog, Start dialog, 
       
      STR_Hint, "Nyní máte otevřené Akční menu.\nStiskem první 
      položky\n""Spustit dialog""\notevřete dialog ""Hello, World !""", "The 
      Action menu is opened now.\nPress first item to open\n""Hello, World !"" 
      dialog.", 
      STR_Error, "Nevybral jste žádného vojáka !!!", "You havn't selected any 
      soldier !!!", 
       
      Teď již máme hotovo vše abychom mohli dialog spustit příkazem check = 
      CreateDialog "RscHelloWorld". Ale....... Tento dialog se nám sice otevře, 
      ale nebude zcela funkční, neboť je ještě zapotřebí vytvořit pár 
      jednoduchých scriptů, pomocí kterých budeme chování dialogu ovládat.  
      První script přidá položku do Akčního menu, kterou se aktivuje dialog a 
      napoví hráči co že to má vlastně udělat. Je to všem velmi dobře známý init.sqs, 
      který obsahuje pouze : 
       
      player AddAction [Localize"STR_AddAction_0", "activatedialog.sqs"] 
      ~0.5 
      Hint Localize"STR_Hint" 
      Exit 
       
      Druhý script je o něco složitější neboť má za úkol aktivovat dialog a 
      iniciovat jeho impicitní nastavení. Je to script activatedialog.sqs, který 
      obsahuje tento kód : 
       
      _check = CreateDialog "RscHelloWorld" 
       
      ; ******* Zde lze vytvořit chybovou rutinu pro případ, že by se dialog 
      neotevřel ***** 
      ;? _check: GoTo "OK" 
      ;TitleText["Něco je špatně dialog nelze otevřít.\nZkuste restartovat misi, 
      nebo tak něco", "Plain"] 
      ;ForceEnd 
      ;Exit 
      ;#OK 
      ;****************************************************************** 
       
      ; ------------- Nastaví hodnoty položek ComboBoxu s IDC 3001 
      ---------------------- 
      _countgrp = Count (Units Group Player) 
      _x = 0 
      lbAdd [3001, Localize"STR_CB_Txt_0"] 
      #Loop1 
      _x = _x + 1 
      _index3001 = _index3001 + [lbAdd [3001, Name (Units Group Player Select 
      _x)]] 
      ? _x < (_countgrp - 1): GoTo "Loop1" 
       
      ; ------------ Nastaví implicitní položku ComboBoxu 
      --------------------------- 
      lbSetCurSel [3001, 0] 
       
      Exit 
       
      No a na závěr vytvoříme poslední, bohužel taky nejsložitější script, který 
      má za úkol zjistit hráčem požadovaná data a vypsat je do textového pole 
      dialogu. Tento script si pojmenujeme třeba onClickGetData.sqs, a to proto, 
      že se spustí při kliknutí na tlačítko "Získej data". Soubor obsahuje 
      následující kód : 
       
      ; ------- Získat hodnoty z vybrané položky 
      CombnoBoxu ------- 
      _cbindex = lbCurSel 3001 
       
      ; ******************** Chybová rutina *************************** 
      ; ***** v případě, že hráč nevybere žádnou položku Combo boxu ***** 
      ? _cbindex == 0: Hint Localize"STR_Error"; Exit 
      ; ****************************************************************** 
       
      ; ---------- Získat údaje o pozici vybraného vojáka --------- 
      _soldiername = lbText [3001, _cbindex] 
      _soldierpos = GetPos (Units Group Player Select _cbindex) 
      _soldierposx = _soldierpos Select 0 
      _soldierposy = _soldierpos Select 1 
      _soldierposz = _soldierpos Select 2 
      Goto "GetAngle" 
      #Return 
      _unitname = Units Group Player Select _cbindex 
       
      ; ------------- Vypsat získané údaje do TextBoxu ------------ 
      ctrlSetText [1003, Format[Localize"STR_TextBox2_2", _soldiername, _soldierposx, 
      _soldierposy, _soldierposz, _angle, _unitname]] 
       
      Exit 
       
       
      ; --------- Subprocedura pro získání úhlu mezi vojákem a hráčem 
      ----------- 
      ; --------- Např. pro použití v příkazu SetDir, příkaz DoWatch 
      ------------ 
      ; --------- totiž ne vždy spolehlivě pracuje 
      ------------------------------ 
      #GetAngle 
      _playerpos = GetPos player 
      _playerposx = _playerpos Select 0 
      _playerposy = _playerpos Select 1 
      _distancex = _soldierposx - _playerposx 
      _distancey = _soldierposy - _playerposy 
      _absgoniometry = Abs(_distancex) + Abs(_distancey) 
       
      _asinderived = _distancex / _absgoniometry 
      _acosderived = _distancey / _absgoniometry 
       
      ? _asinderived >= 0 AND _acosderived >= 0: _angle = Asin(_asinderived) 
      ? _asinderived >= 0 AND _acosderived < 0: _angle = 180 - Asin(_asinderived) 
      ? _asinderived < 0 AND _acosderived < 0: _angle = 180 + Abs(Asin(_asinderived)) 
      ? _asinderived < 0 AND _acosderived >= 0: _angle = 360 - Abs(Asin(_asinderived)) 
       
      Goto "Return" 
       
       
      No a teď je to již opravdu vše. Pokud jste postupovali přesně podle tohoto 
      návodu, měl by se Vám dialog "Hello, World !" bezproblémů otevřít a 
      správně pracovat. Pro jistotu si však vše co je výše uvedeno můžete 
      stáhnout
      odstud. 
       
          
       |