9 Editor map
Editor map pro hru 8 Kingdoms je jednoduchým nástrojem pro vytváření nových či úpravu existujících map včetně rozestavění jednotek, budov, a veškerého počátečního nastavení pro danou hru. Byl programován v C++ Builderu 6 díky jeho vlastnosti tvořit rychle a snadno vizuální aplikace pro Win32 a z toho též plyne, že je spustitelný pouze na této platformě. Původně byl vyvíjen pouze jako pracovní nástroj pro vývojáře k pohodlné tvorbě a editaci map, poté však byl upraven a vylepšen, aby mohl být součástí finální Release verze hry. Hráči je tedy poskytnut další nástroj k tomu, aby si hru utvořil ještě zajímavější.
9.1 Architektura vrstev
Většina aplikační logiky v editoru je implementována v rámci nějaké vrstvy. Každá vrstva je reprezentována třídou v souboru uMapEditorLayer.cpp. Všechny třídy vrstev jsou odvozeny od společného předka TMapEditorLayer, jenž obsahuje virtuální metody, které jsou potom hromadně volány pro všechny vrstvy. Následující tabulka udává výčet a účel všech implementovaných vrstev:

Jméno třídy vrstvy | Popis vrstvy
TTerrainHeightMapLayer | Reprezentuje vrstvu převýšení terénů. Pomocí ní jsou vykreslovány různé odstíny pro různé úrovně převýšení terénů.
TTerrainTypeMapLayer | Reprezentuje vrstvu typů terénů. Pomocí ní jsou vykreslovány různé textury pro různé typy terénů.
THexMapLayer | Reprezentuje vrstvu hexové mapy. Vykresluje hexovou mřížku a také předává informace o daném hexu.
TMapBoundariesLayer | Reprezentuje vrstvu ohraničení mapy. Pouze vykresluje nehratelné oblasti na okraji mapy.
TBuildingMapLayer | Reprezentuje vrstvu editace budov. Vykresluje obrázky budov a předává informace o jejich vlastnostech.
TUnitMapLayer | Reprezentuje vrstvu editace jednotek. Vykresluje obrázky jednotek a předává informace o jejich vlastnostech.
TKingdomsMapLayer | Reprezentuje vrstvu rozdělení mapy na království. Pomocí ní jsou zobrazena jednotlivá království a popřípadě i jejich středy.
TUnitOccurranceMapLayer | Reprezentuje vrstvu výskytu speciálních jednotek na hexech. Stará se o vizuální zobrazování těchto výskytů a předává o nich konkrétní informace.
TPathfindMapLayer | Reprezentuje vrstvu pro testování vyhledávání cesty. Tato vrstva byla použita pouze pro ladící a testovací účely a v Release verzi editoru není vůbec volána. Vyhledává a vykresluje na mapě optimální cestu.
TCityLayer | Reprezentuje vrstvu měst. Stará se o jejich zobrazování a předávání informací o jejich vlastnostech.
THexPreselLayer | Reprezentuje vrstvu kurzoru pro hex, nad kterým má uživatel aktuálně myš. Má na starosti pouze vykreslení jeho zvýraznění.
TCursorLayer | Reprezentuje vrstvu kurzoru aktuálně vybraného hexu. Má na starosti pouze vykreslení jeho zvýraznění.

Tabulka 9.1: Přehled vrstev
Každá z těchto tříd má v aplikaci pouze jednu instanci, jenž jsou postupně uloženy v kontajneru TList. Je i určeno v jakém pořadí jsou vrstvy přidávány - tím je pak určeno i pořadí volání jejich virtuálních metod. Všechny virtuální metody, jenž může implementovat jakákoliv vrstva jsou uvedeny v následující tabulce:

Jméno metody vrstvy | Popis metody
Draw(TCanvas* can, TRect* rectPixels, TRect* rectHexes) | Vykresluje obsah vrstvy na canvas. Parametr rectPixels udává obdélník pixelů, jenž se mají vykreslovat, parametr rectHexes pak obdélník hexů zadaný jejich souřadnicemi.
MouseOver(int X, int Y) | Zpracovává pro danou vrstvu událost, kdy je myš nad hexem se souřadnicemi [X,Y].
MouseUp(int X, int Y) | Zpracovává pro danou vrstvu událost, kdy je kliknuto myší nad hexem se souřadnicemi [X,Y].
MouseDown(int X, int Y) | Zpracovává pro danou vrstvu událost, kdy je stisknuto tlačítko myši nad hexem se souřadnicemi [X,Y].
HexSelected(int X, int Y) | Zpracovává pro danou vrstvu událost, kdy je hex vybrán uživatelem [X,Y].

Tabulka 9.2: Virtuální metody vrstev
Pořadí vrstev má například přímý vliv na vykreslování (volání metod Draw). Toto pořadí si však může uživatel přímo v editoru měnit, či například i vypínat vykreslování jednotlivých vrstev a zobrazit si tak přehledněji informace, které chce.
9.2 Napojení na Resource Manager
Editor map samozřejmě potřebuje využívat zdroje, jenž jsou používány i ve hře samotné - jedná se například o textové zdroje, informace o jednotkách a budovách. Dále potřebuje být propojeno vytváření, načítání a ukládání mapy.
Celá inicializace práce s Resource managerem začíná jeho inicializací (volání RMInit v Editor.cpp). V konstruktoru hlavního formuláře editoru (viz volání TfrmMapEditor::TfrmMapEditor(TComponent* Owner) v ufrmMapEditor.cpp) jsou pomocí Message systému instanciovány resource managery pro mapu, budovy, jednotky a textové řetězce. Poté je vybrána angličtina jako standardní jazyk pro editor.
Při vytváření nové mapy je potřeba vyplnit požadovanými hodnotami strukturu TMapInfo (viz common/rm/rmmap.h) - ta obsahuje rozměry, jméno a popis mapy, vybrané role a jejich vlastnosti, jejich počáteční diplomatické nastavení. Poté je mapa standardně inicializována sadou get metod třídy TRM_map_i. Výše popsané operace odpovídají kódu metody TfrmMapEditor::butNewMapClick(TObject *Sender) v ufrmMapEditor.cpp. Pro otevírání existujících map a jejich ukládání jsou vždy (po příslušných validacích) volány set metody třídy TRM_map_i (pro načítání existující mapy pouze pokud je nějaká načtena) a poté i get metody stejné třídy.
9.3 Generování náhodných map
Generátor náhodných map vytváří náhodný povrch v právě otevřené mapě. Jeho cílem je pouze návrh možného uspořádání převážně terénů a výšek a nezatěžovat s jejich pracným vytváření uživatele. Ten si může postupně vybrat několik návrhů a vybrat si ten, který se mu nejvíce zamlouvá.
V mapě je náhodné generován terén (jsou umisťovány všechny typy kromě terénů města, bažin a skal) a výšky (všechny stupně od výšek stupně 1 až po stupeň 4). Dále jsou také náhodně umístěny výskyty speciálních jednotek. Zbývající akce, které uživatel musí následně ještě provést, aby bylo na mapě možné hrát, je pouze umístění měst a království a určení výchozí polohy hráčů (například vložením stavitele na příslušné místo). Pro vlastní generování se volá funkce generateRandomMap.

Typ | Způsob generování
Výšky | Jako první operace poté, kdy se nastaví všechny výšky na 1, je náhodné umístění vrcholků kopců, jejichž počet určí uživatel, v maximální výšce, kterou také uživatel určí. Následně se vytvoří vlastní pohoří, podle atributu strmosti kopců, kterou zadá uživatel. Při generování je tedy využito pole reálných hodnot, které se následně převádí do mapy s hodnotami výšek pouze celočíselnými (jejichž počet je navíc omezen na pět), avšak pole reálných hodnot se zachovává pro další použití.
Lesy | Následuje vytvoření center lesů, jejichž počet a pravděpodobnost dalšího rozšíření zadá uživatel. Po rozšíření lesů kolem jejich center může, podle zadaných parametrů, dojít ke změně lesa na hvozd. Podmínky tvoří například počet lesů na okolních hexech.
Řeky | Po umístění pramenů řek dochází k jejich "rozlití" do terénu. Zde se využívá ještě obraz mapy v reálných čísel, aby se našel největší spád a tedy koryto řeky. Řeka je generována tedy tak, aby tekla vždy dolů, pokud může, jinak po rovině. V nížině a nebo když řeka nemá již kam téci vytváří "jezera" (reprezentované terénem moře).
Magické území | Nakonec se ještě umístí oblasti s výskytem speciálních jednotek a to pouze na místa, kde se nechá postavit budova.

Tabulka 9.3: Postup při vytváření mapy.
9.4 Vykreslování
Vykreslování mapy a celého herního plánu je v editoru realizováno pomocí VCL komponenty PaintBox (třída TPaintBox). Je použito prosté softwarové vykreslování bitmap přímo na Canvas, žádná externí knihovna (DirectX, OpenGL) nebyla použita. Vykresluje se vždy pouze nejmenší konvexní obdélník pixelů, jenž ohraničuje všechny hexy, ze kterých je aktuálně alespoň kousek vidět. Vykreslování je realizováno voláním virtuálních metod Draw(TCanvas* can, TRect* rectPixels, TRect* rectHexes) na každé vrstvě. Jak již bylo řečeno v odstavci 9.1 - pořadí vrstev naskládaných v kontajneru ovlivňuje i pořadí vykreslování bitmap přes sebe. Metoda Draw kromě konvexního obdélníka pixelů má další parametr - obdélník aktuálně zobrazovaných hexů zadaný jejich souřadnicemi. To zaručuje, že entity, které nemá smysl uvažovat na pixelové úrovni (jako budovy či jednotky) budou vykreslovány pouze pokud jsou vidět (tj. uživatel má focus mapy na oblasti, kde se jednotka skutečně nachází).
9.5 Editace království
Editor map samozřejmě podporuje i úplnou editaci hranic království. Aby uživatel nemusel pracně klikat hex po hexu celou mapu, byla zavedena tzv. centra království. Uživatel označí hexy center pro každé království a po kliknutí na tlačítko "Generate Area From Center" je spuštěn algoritmus floodingu (volání funkce computeBorders v uComputeBorders.cpp), jenž postupně zaplavuje mapu od center království než narazí na jiné zaplavené oblasti. Ve výsledku to znamená, že království určené svým centrem se sestává z hexů, jenž jsou měřeno hexovou vzdáleností nejblíže právě k centru svého království. Hexy, jenž mají stejnou vzdálenost od dvou či více center království připadnou tomu království, jenž má nižší ID. Uživatel si samozřejmě poté může území takto vygenerovaných království sám upravit dle svých požadavků. Centra království jsou též ukládána do mapy, přestože v samotné hře nemají žádný význam.
9.6 Editace měst
Jedním z netriviálních problémů v editoru map je též editace měst. Město je bráno v podstatě pouze jako terén ale musí uchovávat nějaké další informace nejen pouze na úrovni samotného hexu - například vlastníka, či příjem. Velikost měst je pravidly omezena na 7 hexů, jenž musí navíc tvořit souvislou oblast. Pro práci při editaci s hexy slouží následující metody třídy TfrmMapEditor (viz ufrmMapEditor.cpp).

Jméno metody vrstvy | Popis metody
std::list<int> getCityHexBorderDirections(int x,int y) | Vrátí kontajner čísel určujících směry hranic celého města v rámci jednoho hexu města se souřadnicemi [x,y]. Podle toho jsou poté vykresleny hranice celého města.
int getCityOwner(int x,int y) | Vrátí ID role, jenž je určena jako vlastník města, jenž obsahuje hex se souřadnicemi [x,y].
int getCityID(int x,int y) | Vrátí ID města jenž obsahuje hex se souřadnicemi [x,y].
void addingCityHex(int x,int y) | Přidává hex města na souřadnici [x,y]. Je vytvořen zcela nový záznam o městu, nebo je nějaké existující město rozšířeno o jeden hex (pokud není již předtím maximálně veliké a nový hex s ním sousedí).
void removingCityHex(int x,int y) | Odebírá hex města na souřadnici [x,y]. Město může buď úplně zaniknout, nebo se může rozpadnout na více nesouvislých komponent (maximálně na tři) - odebráním hexu města může tedy paradoxně měst i přibýt.

Tabulka 9.4: Metody pro editaci měst
9.7 Nastavení diplomacie
Editor map umožňuje pro role, jenž jsou pro mapu vybrány určit též počáteční diplomatické vztahy (více o Diplomacii viz odstavec 4.2.2) jenž budou platné při začátku hry. Pomocí formuláře lze snadno vybrat oficiální vztah. Protože role v editoru jsou nezávislé na konkrétním hráči (AI nebo člověk), je nutné doplnit i další vlastnosti diplomatického vztahu (viz TDipRelation a TRelationshipProperties v ai/diplomacy/diptypes.h), které jsou poté ukládány do mapy. Navržené vztahy (položka offeredrs) jsou inicializovány na stejný, jako je vybraný oficiální (položka rs). Oba vztahy jsou protihráčům určeny jako známé (příznak offer_seen_by_enemy) a hodnoty důvěr a odhadovaných důvěr (položky belief a guess_belief) jsou určeny z oficiálního vztahu pomocí maker DEFAULT_BELIEF_FOR_... v ai/diplomacy/dipcoefs.h. Hodnoty těchto maker jsou průměrem maximální a minimální hodnoty důvěr pro daný diplomatický vztah.