Might and Magic VII na Androidu: postavte si port sami

Sedmadvacet let stará hra na telefonu, česky, s dotykovým ovládáním a bez hledání souborů ve složkách. Postavil jsem si vlastní aplikaci a celý postup sesypal do jednoho promptu pro Claude Code. Zkopírujte si ho a projděte to taky, potřebujete k tomu jen vlastní kopii hry z GOGu.
Might and Magic VII vyšla v roce 1999 a pořád patří k tomu nejlepšímu, co se dá hrát po tazích jednou rukou. Na telefon se oficiálně nikdy nedostala. Existuje ale open source engine OpenEnroth, který původní hru umí spustit na dnešních systémech včetně Androidu. Herní data si k němu musíte dodat z koupené hry a aplikaci si sestavit sami.
Oficiální cesta počítá s tím, že jste vývojář: přeložíte engine, vyrobíte aplikaci a herní data pak nakopírujete do složky v telefonu, kam vás novější Androidy pořádně nepustí. To mi přišlo zbytečně složité, tak jsem postavil jedinou aplikaci, která má data v sobě, po instalaci si je sama rozbalí a rovnou spustí hru. Celý postup i se slepými uličkami jsem pak sesypal do jednoho promptu, který si můžete zkopírovat níž.
Co z toho vyleze
Jedna aplikace s vaším názvem a s původní ikonou hry. Po nainstalování ukáže ukazatel průběhu, rozbalí si přes šest set megabajtů herních dat a spustí hru. Žádné kopírování souborů do telefonu, žádné hledání složky Android/data.

Hra jde i česky. GOG prodává jen anglickou verzi, ale fanouškovský překlad se dá nainstalovat do hry na počítači a data se pak do aplikace zabalí už počeštěná. Dabing zůstává anglický, přeložené jsou texty a obrázky tlačítek.

Co musíte mít připravené
- Legálně koupenou hru Might and Magic VII z GOG.com, a hlavně ji mít na počítači nainstalovanou. Stažený instalátor nestačí, data se berou z nainstalované hry.
- Volitelně fanouškovský překlad do češtiny, nainstalovaný do hry ještě před stavbou aplikace.
- Windows 10 nebo 11, zhruba 25 GB volného místa a nainstalovaný Docker Desktop. Bez něj se aplikace nesestaví.
- Git a Python 3. Když chybí, poradí si s tím Claude Code sám.
- Telefon nebo tablet s Androidem 7 a novějším, 64bitovým procesorem ARM a podporou OpenGL ES 3.2, tedy prakticky každé zařízení zhruba od roku 2017. Volného místa je potřeba asi 1,3 GB.
- Zhruba hodinu času při prvním průchodu, z toho většinu zabere stahování.
Jedna věc je důležitá a v promptu je napsaná dvakrát: hotová aplikace obsahuje vaše herní data z GOGu. Je jen pro vás, nikam se nenahrává a nikomu neposílá. Kdo ji chce taky, musí mít vlastní kopii hry a postavit si vlastní. Engine OpenEnroth je pod licencí LGPL.
Jak to spustit
Otevřete si Claude Code v pracovní složce na disku, ideálně bez mezer v cestě, a vložte do něj celý text níž. Hned nahoře v něm je odstavec MOJE ÚDAJE, kde si přepíšete cestu k nainstalované hře, název aplikace, identifikátor balíčku a jazyk. Potom už jen odsouhlasíte plán, který vám Claude napíše, a necháte ho pracovat.
Prompt staví port od nuly, takže k němu nic dalšího nepotřebujete. Kdo si chce ušetřit čas, najde hotovou upravenou kopii enginu i s nástroji na sestavení ve veřejném repozitáři MaM-android; naše změny jsou v něm i jako samostatné záplaty. Herní data v něm samozřejmě nejsou, ta musí mít každý svoje.
Prompt pro Claude Code
Chci si pro vlastní potřebu postavit Android port hry Might and Magic VII: For Blood and Honor
jako JEDNO samostatné APK, které po instalaci rovnou funguje. Vlastním legální kopii z GOG.com
a mám ji NAINSTALOVANOU na tomhle PC. APK bude obsahovat moje herní data, takže je jen pro mě
a nikam se nesmí nahrávat ani sdílet. Na to mě na konci upozorni.
MOJE ÚDAJE (doplň / uprav):
- Cesta k nainstalované hře: C:\GOG Games\Might and Magic 7
- Pracovní složka projektu: D:\Projekty\MaM7 (ideálně BEZ mezer v cestě)
- Název aplikace v telefonu: MaM 7
- ID balíčku: cz.mm7.game
- Jazyk hry: čeština (fanouškovský překlad už mám nainstalovaný ve hře, tj. přepsané
DATA\Events.lod a DATA\ICONS.LOD) / nebo: angličtina (originál GOG)
- Mám Docker Desktop: ano. Mám Android Studio (SDK + emulátor): ano/ne.
ZÁSADNÍ PRAVIDLA:
1. Do složky s originální hrou NIKDY nezapisuj, jen z ní čti. Pracuj na kopii dat ve složce projektu.
2. Než začneš cokoli velkého stahovat, kopírovat nebo stavět, napiš mi krátce plán a počkej
na moje „ano". Potom už pracuj samostatně a neptej se na každý krok.
3. Nic netvrď bez ověření. U každé věci mi řekni, jestli je ověřená (a jak), nebo jen předpokládaná.
4. V ničem, co uvidím v telefonu (název, ikona, ID balíčku, název APK souboru), nesmí být
„OpenEnroth". Je to můj projekt. Engine je LGPL, na to mě jen upozorni.
5. Komunikuj česky.
KROK 0: OVĚŘ PŘEDPOKLADY (nic přitom neměň). Když něco chybí, zastav se a řekni mi, co mám doplnit:
- Hra je opravdu NAINSTALOVANÁ, nejen stažený instalátor: ve složce hry existují podsložky
ANIMS, DATA, MUSIC, SOUNDS a v nich soubory anims\magic7.vid, anims\might7.vid,
data\bitmaps.lod, data\events.lod, data\games.lod, data\icons.lod, data\sprites.lod,
data\d3dbitmap.hwl, data\d3dsprite.hwl, sounds\audio.snd a hudba music\*.mp3.
Pokud najdeš jen setup_might_and_magic_7*.exe, řekni mi, ať hru nejdřív nainstaluju.
- Jazyk dat: přečti global.txt z DATA\Events.lod (viz sekce E) a řekni mi, jestli je hra
česky nebo anglicky. Pokud chci češtinu a data jsou anglická, zastav se.
- Docker Desktop běží a není pozastavený (docker info / docker ps projde).
- Je k dispozici git a Python 3 s Pillow. Je dost místa na disku (aspoň ~25 GB).
- Zjisti, jestli mám Android SDK a emulátor (%LOCALAPPDATA%\Android\Sdk, emulator -list-avds).
TECHNICKÝ POSTUP (ověřená cesta, drž se jí):
A) Engine
- Použij open-source engine OpenEnroth (github.com/OpenEnroth/OpenEnroth), klonuj mělce včetně
submodulů. Android projekt je ve složce android/ hlavního repa (samostatné repo
OpenEnroth_Android je archivované, to nepoužívej).
- Engine na Androidu hledá data mimo jiné v INTERNÍM úložišti aplikace (getFilesDir).
Ověř si to v src/Application/Startup/PathResolver.cpp a GameStarter.cpp. Díky tomu není
potřeba sahat do Android/data, kam novější Androidy uživatele nepustí.
B) Build: jen v Dockeru, ne nativně na Windows
- Nativní build na Windows je slepá ulička: Gradle 7.4 + AGP 7.3.1 potřebuje JDK 17 (ne 21),
NDK má problém s mezerami v cestě a LuaJIT si při cross-kompilaci staví hostitelské nástroje
(minilua, buildvm), což build skripty umí jen na Linuxu/macOS.
- Udělej Docker image z ubuntu:24.04 s: openjdk-17, git, ninja, build-essential, rsync, unzip,
wget; Android cmdline-tools + sdkmanager: platform-tools, platforms;android-31,
build-tools;30.0.3, ndk;28.1.13356709 (verzi NDK ověř v android/openenroth/build.gradle).
- CMake z Ubuntu (3.28) NESTAČÍ, submodul ztd_text chce 3.31+. Stáhni oficiální tarball
CMake 3.31.x od Kitware do /opt/cmake a dej ho na PATH před systémový.
- Licence Android SDK neodklikávej za mě přes „yes |". Pokud mám Android Studio, zkopíruj moje
už odsouhlasené soubory z %LOCALAPPDATA%\Android\Sdk\licenses do image. Jinak se mě zeptej.
- Build skript v kontejneru: rsync repa z read-only mountu /src do pojmenovaného volume /work
(build na bind-mountu z Windows je pomalý), opravit CRLF v gradlew (sed) a spouštět ho přes
„bash ./gradlew", ne „sh". Gradle cache drž v dalším volume.
- Závislosti (SDL3, FFmpeg, OpenAL…) si CMake stáhne předkompilované z OpenEnroth_Dependencies,
nestav je ručně.
- Stav jen ABI arm64-v8a (proměnná prostředí GITHUBARCH=arm64-v8a), task assembleRelease.
- Podepisování: vygeneruj keytoolem vlastní keystore do výstupní složky a předej ho přes
SIGNING_KEYSTORE / SIGNING_STORE_PASSWORD / SIGNING_KEY_ALIAS / SIGNING_KEY_PASSWORD.
Keystore si musím schovat, jinak příští verze nepůjde nainstalovat přes starou.
- Pokud Docker Desktop nejde spustit s chybou „…sock.stale: The file cannot be accessed by the
system", jsou to osiřelé AF_UNIX sockety. Nejdou smazat, ale jde PŘEJMENOVAT celé složky
%LOCALAPPDATA%\Docker\run a %LOCALAPPDATA%\docker-secrets-engine (když Docker neběží).
Nikdy neklikej na „Reset to factory defaults". Pokud je Docker ručně pozastavený (paused),
neobcházej to a řekni mi to.
C) Data uvnitř APK + instalátor
- Z instalace zkopíruj jen složky ANIMS, DATA, MUSIC, SOUNDS (cca 634 MB) do
<projekt>\gamedata\mm7\. Do build.gradle přidej volitelnou property GAME_DATA_DIR, která
přidá tuhle složku do sourceSets.main.assets.srcDirs, a aaptOptions noCompress pro
lod/LOD, vid/VID, snd/SND, hwl/HWL, mp3/MP3 (rychlé rozbalování, openFd funguje).
- Napiš novou Activity „DataInstallerActivity" (čistá Java, bez XML, minSdk 16) a nastav ji
v manifestu jako MAIN/LAUNCHER místo herní aktivity. Při prvním spuštění: zkontroluje volné
místo, rekurzivně zkopíruje assets/mm7/* do getFilesDir() s ukazatelem průběhu v MB
(české texty ve values-cs), drží zapnutou obrazovku, zapíše značkový soubor vázaný na
lastUpdateTime balíčku a spustí herní aktivitu. Když značka existuje, spouští hru rovnou.
D) Název, ID, ikona
- app_name = můj název, applicationId = moje ID (namespace Java tříd nech org.openenroth.game,
kvůli JNI/SDL), výstupní soubor pojmenuj podle mého názvu.
- Ikonu vytáhni z originálního MM7-Rel.exe (skupina ikon obsahuje 64×64 v plných barvách, gryf).
Nejjednodušší je Python + ctypes (LoadLibraryEx jako datafile, RT_GROUP_ICON/RT_ICON) + Pillow.
Zvětšuj nejdřív NEAREST na 512 px, pak LANCZOS na cílové velikosti, ať zůstane pixel-art ostrý.
Vygeneruj mipmap-*/ic_launcher.png, ic_launcher_round.png a ic_launcher_foreground.png
(108dp plátno, ikona v 66dp bezpečné zóně) a v mipmap-anydpi-v26 přepni foreground na
@mipmap/ic_launcher_foreground, pozadí černé.
E) Čeština (pokud ji chci)
- GOG verze je jen anglická. Ověř jazyk tak, že si napíšeš malý parser LOD archivu
(hlavička „LOD\0", adresář na 0x100, položky po 32 bajtech, obsah zlib) a přečteš global.txt
z Events.lod. Neprohledávej binárku textově, obsah je komprimovaný.
- Fanouškovské překlady shazují OpenEnroth na dvou věcech, které původní hra tolerovala.
Oprav je V ENGINU, ne v datech:
1) Textové tabulky končí DOSovým znakem 0x1A, hlásí se to jako „'' is not a number".
V ResourceManager::eventsData() u souborů *.txt odřízni koncový bajt 0x1A.
2) Přeložené obrázky v ICONS.LOD mají v hlavičce pole size = velikost celého BMP souboru
místo šířka×výška, hlásí se to jako „Cannot decode LOD entry … as LOD image".
V lod::detectImage() změň podmínku header.size == w*h na header.size >= w*h
(skutečný počet pixelů se stejně kontroluje po dekompresi).
- Než pustíš build, porovnej si česká a anglická data strukturálně (počty sloupců, kontrolní
znaky, hlavičky obrázků a fontů), ať neladíš pád po pádu. Jiný překlad může mít jiné chyby.
F) Pád SDL při změně schránky
- SDL 3.2.22 padá (strcmp NULL v nativním clipboard callbacku), když se za běhu změní schránka.
V herní aktivitě (extends SDLActivity) po super.onCreate() odregistruj mClipboardHandler
z ClipboardManageru. Hra schránku nepotřebuje.
G) Dotykové ovládání v černých pruzích
- Hra je 4:3 uprostřed širokého displeje, vlevo a vpravo jsou černé pruhy. Šířka pruhu
= (šířka − výška×4/3)/2, minimálně ~110 dp. Napiš vlastní ViewGroup „TouchControls" (čistá Java),
přidej ji v onCreate do SDLActivity.mLayout nad herní surface. Samotný kontejner nesmí
zachytávat dotyky, aby dotyk do hry dál fungoval jako levé kliknutí.
- Tlačítka: zaoblené obdélníky, poloprůhledné bílé, při stisku zlaté. Klávesy posílej přes
SDLActivity.onNativeKeyDown/Up (stisk = down, puštění = up). Ikony udělej jako vektorové
drawably (res/drawable, 24dp viewport), kvůli nim nastav minSdkVersion 24 (engine stejně
potřebuje OpenGL ES 3.2, tedy Android 7+).
- LEVÝ pruh, tři skupiny nad sebou:
1) nahoře 2 řádky po 3 tlačítkách, přesně v tomto pořadí:
1. řádek (pohled): Del (pohled dolů), PgDn (pohled nahoru), End (vycentrovat pohled)
2. řádek (let): Ins (let dolů), Home (přistát), PgUp (let nahoru)
2) uprostřed 2 sloupce: Esc, „Y křik" (Y = zavolání postav) / Mezera, Enter /
ikona meče (klávesa A = útok), ikona hůlky (S = rychlé kouzlo)
3) dole 2 sloupce: šipka doleva, šipka doprava (otáčení)
- PRAVÝ pruh:
nahoře: „Myš L", „Myš P" / ikona batohu (I = inventář), ikona mapy (M = mapa) / „X skok", „B skip"
dole uprostřed: šipka nahoru (dopředu) a přímo pod ní bez mezery šipka dolů (dozadu),
samostatně, s volným místem kolem sebe.
- Ikony jsou bez písmen (jen obrázek). Popisky s textem mají jen klávesy bez ikony.
- Velikost písma popisku se přizpůsobí šířce tlačítka (nejvýš ~84 % šířky), jinak se „Home"
a „PgDn" v užších tlačítkách po třech nevejdou.
- „Myš L" / „Myš P": přepínač, výchozí je L. Po zmáčknutí „Myš P" zůstane svítit a zapne se
průhledná celoplošná vrstva. Další dotyk do hry se pošle jako PRAVÉ tlačítko myši přes
SDLActivity.onNativeMouse (BUTTON_SECONDARY: ACTION_DOWN, při pohybu ACTION_MOVE, při
puštění state 0 + ACTION_UP) a drží po dobu držení prstu, po puštění se „Myš P" sama vypne.
- Tablety (poměr stran pod 1,9:1, třeba 16:10): přirozené černé pruhy jsou na tlačítka moc
úzké. Pruh tam má aspoň 150 dp a herní surface zúžíš okraji vlevo a vpravo (MarginLayoutParams,
okraj = šířka pruhu), engine si 4:3 obraz vejde mezi pruhy sám. Pozadí mLayout nastav černé.
Telefony (2:1 a širší) nech beze změny, pruh = (šířka − výška×4/3)/2, minimálně 110 dp.
- Na tabletu je v levém pruhu pod prostřední skupinou volné místo. Meč (A) a hůlku (S) tam
proto vyjmi z prostřední skupiny a polož je jako samostatný řádek hned nad šipky otáčení
(mezera jen jako mezi řádky). Esc, „Y křik", Mezera a Enter zůstanou nahoře. Na telefonu
zůstanou meč a hůlka v prostřední skupině.
- Systémové lišty: SDL je skrývá starými příznaky, které tablety (panel úloh, navigační lišta)
ignorují a lišta pak zakryje spodek hry i spodní tlačítka. V onWindowFocusChanged je skryj
i přes WindowInsetsController (hide(systemBars()), BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE)
a na mLayout nastav OnApplyWindowInsetsListener, který dá mLayout padding podle
insets.getInsets(systemBars()). Výřez displeje (displayCutout) do paddingu NEPOČÍTEJ,
SDL kreslí i do výřezu a černé pruhy ho zakryjí, jinak se rozbije rozložení na telefonu.
- Dotyk přes celoplošnou vrstvu pro pravé tlačítko myši přepočítej do souřadnic herní surface
(x + vrstva.getLeft() − surface.getLeft()), jinak na tabletu klikáš vedle.
- Výchozí klávesy enginu pro kontrolu: šipky pohyb a otáčení, A útok, S rychlé kouzlo,
I inventář, M mapa, X skok, B přeskočit tah v tahovém režimu, Y křik, Mezera interakce,
Enter tahový režim, Del pohled dolů, PgDn pohled nahoru, End vycentrovat pohled, Ins let dolů,
Home přistát, PgUp let nahoru, Esc zavírá okna, T kalendář.
G1) Klávesnice pro psaní textu
- Jméno postavy při tvorbě družiny, název uložené hry a částka v bance se píšou klávesnicí.
Engine má vlastní textový vstup přes klávesové události (KeyboardInputHandler::StartTextInput),
sám klávesnici Androidu neukáže. Přidej do PlatformWindow setTextInputActive/isTextInputActive
(SdlWindow: SDL_StartTextInput/SDL_StopTextInput/SDL_TextInputActive, Proxy a Null okno taky)
a v detail::globalProcessMessages() je v každém průchodu slaď se stavem
keyboardInputHandler (psaní probíhá = inputType je Text nebo Number). SDL pak klávesnici
zobrazí i schová a ASCII znaky z ní posílá jako klávesy, takže je engine zpracuje bez další úpravy.
- Pozor na dialog postavy, která má jen text bez voleb (třeba stráž, GUIWindow_BranchlessDialogue):
engine v něm spouští textový vstup jen proto, aby ho zavřela libovolná klávesa, a klávesnice by
pak vyskočila zbytečně. Přidej do TextInputType hodnotu AnyKey (znaky sbírá jako Text, ale
nepočítá se jako psaní) a dialog ať ji používá, kromě otázky EVENT_InputString, kde se opravdu píše.
G2) Sníh na začátku hry
- OpenEnroth má volbu graphics „seasons_change" (stromy a zem podle ročního období), která je
ve výchozím stavu zapnutá. V originálním MM7 nikdy nebyla (jen v MM6). Hra začíná 1. ledna 1168,
takže Smaragdový ostrov je pod sněhem. Změň výchozí hodnotu v src/Application/GameConfig.h
na false. Datum startu (pondělí 1. 1. 1168, 9:00) je správně, neměň ho.
G3) Gamepad
- Engine má vazby pro gamepad (sekce [gamepad] v GameConfig.h: levá páčka chůze a úkroky,
pravá otáčení a pohled, A akce, L1 útok, R1 rychlé kouzlo, Y skok, Start boj po tazích,
L2/R2 let, L3 běh, R3 přistání, křížek vlevo mapa, vpravo úkoly, dolů kniha kouzel, B Escape),
ale na Androidu se k němu nic nedostane: SDL čte gamepad jen ze svého zobrazení (SDLSurface)
a nad ním leží dotykové ovládání. V aktivitě přepiš dispatchKeyEvent a dispatchGenericMotionEvent
a události se zdrojem JOYSTICK/GAMEPAD/DPAD od zařízení, které SDLControllerManager.isDeviceSDLJoystick
zná, předej SDLControllerManager.onNativePadDown/onNativePadUp, resp. handleJoystickMotionEvent.
- Druhá chyba je v enginu samém a projeví se i na PC: KeyboardController (stav „co je právě
drženo", ze kterého KeyboardInputHandler každý snímek čte pohyb, útok, kouzlení a boj po tazích)
poslouchá jen klávesnici. Přidej mu gamepadKeyPressEvent/ReleaseEvent a gamepadAxisEvent
(páčka vychýlená přes polovinu = držená klávesa, pod polovinu se pustí oba směry).
Bez toho jdou gamepadem jen akce vyřizované hned při stisku (křížek, B).
- Y je ve výchozím stavu skok i inventář zároveň. Nech Y jen skok, inventář dej na křížek nahoru
(poznámky, které tam byly, mají záložku v knize úkolů). Uložený openenroth.ini obsahuje všechny
vazby, proto staré rozložení při startu přepiš (GameStarter po načtení configu).
- V nabídkách, oknech, dialozích a domech (všude mimo 3D pohled a hlavní menu) ať gamepad
řídí kurzor myši: páčky jím hýbou (GameWindowHandler, jednou za snímek přes hook volaný
z detail::globalProcessMessages), A je levé tlačítko, X pravé, B Escape, křížek krok kurzoru.
Emulátor gamepad nemá, ověřit to jde jen na telefonu.
G4) Automatické ukládání po pěti minutách
- Každých pět minut hraní (počítej jen čas na herní obrazovce, ne v nabídkách, při videích
a v aréně) ulož hru do auto01.mm7 až auto10.mm7 dokola, nejstarší přepiš, pořadí si pamatuj
v saves/auto.next. Název pozice „Automaticky NN", hláška ve stavovém řádku (cp1250!
řetězec „ulo" "ena" rozděl, clang v NDK jinak hlásí „hex escape sequence out of range").
Načtení pozice a nová hra odpočet začnou znovu. Původní ukládání při přechodu mapy nech.
G5) Cheat: nesmrtelnost a neomezená mana
- Deset stisků klávesy křiku (Y) za sebou, každý do dvou sekund od předchozího a bez jiné
klávesy mezi nimi, zapne příznak cheatImmortal (hláška ve stavovém řádku), dalších deset ho
vypne. Zapnutý: Character::receiveDamage nic neubere, Party::updateCharactersAndHirelingsEmotions
každý snímek doplní zdraví i manu a zruší bezvědomí a smrt. Jen v paměti, nuluj při loadGame,
saveNewGame a Party::Reset. Pozor: Y je zároveň klávesa „Ano", při nulování počítadla porovnávej
klávesy, ne akce. Držení klávesy (opakování) se nepočítá, počítej jen isKeyPressedThisFrame.
G6) Další úpravy, které už máme a jsou popsané v README.md projektu
- Synchronizace uložených pozic do složky zvolené uživatelem (SaveSync.java), teleport mezi
hradem Harmondale a Smaragdovým ostrovem, družina na obřích schodech Titánské pevnosti
(nepropadá pod stupně), karta Úspěchy vypisuje hospody bez výhry v Arcomage, rozšíření
„Stín nad Krajem" (vlastní kraj.lod). Postupuj podle README a patchů nase-upravy-*.patch.
H) Testování: povinné, než mi APK předáš
- Rozeber hotové APK a ověř: podpis (apksigner verify), název a ID (aapt dump badging),
native-code JEN arm64-v8a, všech 29 datových souborů uložených bez komprese, správné LOD uvnitř.
- Pokud mám emulátor z Android Studia: je x86_64 a umí jen OpenGL ES 3.1, kdežto engine vyžaduje
ES 3.2 (pád „assertion context failed" v initializeOpenGLContext). Pro emulátor proto postav
ZVLÁŠTNÍ testovací variantu (GITHUBARCH=x86_64, do jiné výstupní složky) s jednorázovým
patchem aplikovaným jen na pracovní kopii v kontejneru: versionMinor 2→1 v ES větvi
OpenGLRenderer.cpp a „#version 320 es" → „#version 310 es + #extension GL_EXT_texture_buffer
: enable" v OpenGLShader.cpp. Tenhle patch se NESMÍ dostat do APK pro telefon: po každém
emulátorovém buildu smaž android/openenroth/build v pracovním volume, jinak se x86_64
knihovna přimíchá do telefonního APK. Před předáním to zkontroluj.
- Na emulátoru projdi přes adb (input tap/swipe + screencap) a ukaž mi screenshoty:
instalační obrazovku, hlavní menu, tvorbu družiny (kontrola diakritiky), 3D scénu po startu
nové hry (bez sněhu, zelené stromy), tlačítko dopředu (družina se pohne), Del/PgDn/End
(pohled dolů, nahoru a zpět na střed), ikonu mapy,
Esc, kalendář přes adb keyevent 48 (musí ukázat 1. ledna 1168), a „Myš P" podrženou na portrétu postavy
(má se ukázat info okno a po puštění se má přepínač vypnout). U release buildu nefunguje
„run-as", stav zjišťuj z logcatu a screenshotů. První spuštění může překrýt systémová
bublina „Viewing full screen", odklikni ji.
- Tablet: pokud nemám tablet v emulátoru, vytvoř si vlastní AVD (třeba 2000×1250, 240 dpi,
6 GB data) ve složce projektu (ANDROID_AVD_HOME, složku dej do .gitignore) a do lišty zapni
tříbarvovou navigaci (adb shell cmd overlay enable-exclusive --category
com.android.internal.systemui.navbar.threebutton). Ukaž mi hlavní menu na tabletu, psaní
jména postavy s klávesnicí, klik na postavu jen s textem (klávesnice se NESMÍ ukázat)
a totéž na rozměru telefonu (adb shell wm size 2400x1080,
wm density 420, pak wm size reset a wm density reset).
- Emulátor mi NEMAŽ (wipe-data), mám v něm vlastní aplikace. Když v něm dojde místo, testovací
aplikaci odinstaluj a emulátor restartuj. Po testech aplikaci odinstaluj a emulátor vypni.
- Schránku na mém PC nepřepisuj (emulátor ji sdílí).
VÝSTUP:
- Jedno APK ve složce <projekt>\out\, plus keystore tamtéž.
- Na konci mi napiš: přesnou cestu k APK, jak ho dostat do telefonu a nainstalovat (neznámé
zdroje, cca 1,3 GB volného místa, první spuštění rozbaluje data), co přesně je ověřené a co ne
(hlavně: skutečný telefon s ES 3.2 jsi netestoval), co jsi změnil na mém disku (složky,
Docker image a volumes) a že APK s mými daty nesmím šířit.
Dotykové ovládání
Hra je čtyři ku třem, takže na širokém displeji zbydou po stranách černé pruhy. Právě do nich jsem umístil tlačítka, aby nezakrývala obraz. Nahoře vlevo jsou dvě trojice kláves: první je na rozhlížení nahoru, dolů a zpátky na střed, druhá na let, tedy stoupání, klesání a přistání. Pod nimi je Esc, křik na postavy, interakce, tahový režim, útok a rychlé kouzlo, úplně dole otáčení.

Vpravo je inventář, mapa, skok, přeskočení tahu, šipky dopředu a dozadu a přepínač pravého tlačítka myši, bez kterého by v téhle hře nešla polovina věcí. Dotyk do herní plochy funguje dál jako kliknutí levým tlačítkem.
Na tabletu je obrazovka méně podlouhlá, takže by přirozené černé pruhy byly na tlačítka moc úzké. Aplikace je tam proto rozšíří a herní obraz mezi ně zúží. Zároveň si trochu přerovná tlačítka: meč a hůlka se přesunou dolů nad šipky otáčení, kde je na tabletu volné místo a kam palec dosáhne. Na telefonu zůstává všechno jako dřív. Systémové lišty se schovávají i tam, kde starý způsob skrývání nefunguje, aby panel úloh nezakrýval spodek hry.
Psaní textu má vlastní kapitolu. Jméno postavy, název uložené pozice a částka v bance se zadávají klávesnicí, jenže engine si klávesnici Androidu sám nevyvolá. Prompt proto přidává propojení, po kterém se klávesnice ukáže vždycky, když hra čeká na text, a zase zmizí. Má to jednu zrádnost: hra spouští textový vstup i u dialogů, kde se nic nepíše a jen se čeká na libovolnou klávesu, takže by klávesnice vyskakovala třeba při každém oslovení stráže. Ty případy se musí odlišit.
Uložené hry v telefonu i na počítači
Poslední přírůstek řeší otravnou věc: hra ukládá do soukromé složky aplikace, kam se jiné programy nedostanou. Rozehraná partie tak zůstane uvězněná v telefonu. Aplikace proto umí savy porovnávat s libovolnou složkou, kterou jí jednou ukážete. Když si do ní necháte synchronizovat cloudové úložiště, máte uložené pozice i na počítači.
- Soubor změněný jen na jedné straně se zkopíruje na druhou.
- Když se změnil na obou stranách a liší se, vyhraje novější a ten starší se odloží do podsložky se zálohami, s datem a s tím, odkud pochází.
- Nemaže se nikdy nic. Pozice smazaná ve hře se ze složky zase vrátí, takže se o save nedá přijít omylem.
- Synchronizuje se před spuštěním hry a pak pokaždé, když aplikaci odložíte na pozadí nebo se do ní vrátíte.
Napojení na konkrétní cloud v aplikaci schválně není. Stačí obyčejná složka a o zbytek se postará ta synchronizační aplikace, kterou už používáte. Jedna věc je ale důležitá: novou verzi instalujte vždycky přes tu starou, nikdy ji předtím neodinstalovávejte. Odinstalace uložené pozice smaže.
Co hra umí navíc proti originálu
Část promptu už nejsou opravy, ale přídavky. Žádný z nich není povinný, kdo je nechce, tu část prostě vymaže.
- Ovládání gamepadem. Engine vazby pro ovladač má, jenže na Androidu se k němu nic nedostane, protože nad herní plochou leží dotyková tlačítka. Páčky teď chodí i do hry a v nabídkách, obchodech a dialozích jimi hýbete kurzorem myši.
- Automatické ukládání každých pět minut hraní, do deseti pozic dokola. Počítá se jen čas na herní obrazovce, ne v nabídkách a videích.
- Cesta zpátky na Smaragdový ostrov. V původní hře se tam po odplutí vrátit nedá; teď jsou na hradě Harmondale a na ostrově dvě propojené plošiny, nad kterými se třpytí částice, a vstup na ně se zeptá úplně stejným oknem jako běžný přechod mezi mapami.
- Nesmrtelnost a neomezená mana na deset rychlých stisků klávesy křiku, dalších deset to zase vypne. Je to jen v paměti, do uložené pozice se to nepropíše.
- Družina na obřích schodech v Titánské pevnosti nepropadává pod stupně, karta Úspěchy vypisuje i hospody, kde se ještě nevyhrálo v Arcomage, a sáhlo se i na vlastní rozšíření Stín nad Krajem.
U plošin na ostrov si hra hlídá i drobnosti: nenaskočí hned po příchodu na mapu, nespustí se opakovaně, dokud z nich nesejdete, mlčí v tahovém režimu a ta na ostrově začne fungovat až potom, co družina ostrov poprvé opustí. Jinak by šlo přeskočit úvodní úkoly.
Na čem to drhlo
Prompt je tak podrobný proto, že většina jeho bodů vznikla z něčeho, co nefungovalo. Stálo mě to několik hodin a vy je díky tomu přeskočíte.
- Sestavení přímo ve Windows je slepá ulička. Nástroje si při překladu potřebují postavit pomocné programy pro Linux a vadí jim mezery v cestách. Proto se všechno staví v Dockeru.
- Fanouškovská čeština shazuje engine na dvou drobnostech, které původní hra tolerovala: na koncovém znaku v textových tabulkách a na hlavičce přeložených obrázků. Opravuje se to v enginu, ne v datech.
- Emulátor z Android Studia umí jen OpenGL ES 3.1, kdežto engine chce 3.2. Testovací verze pro emulátor se proto staví zvlášť a ta úprava se nesmí dostat do aplikace pro telefon.
- Hra začíná 1. ledna 1168 a engine má ve výchozím stavu zapnutá roční období, která v sedmičce nikdy nebyla. Bez zásahu tak celý začátek hry probíhá pod sněhem.
Prompt odkazuje na konkrétní verze nástrojů platné v září 2026. Až se OpenEnroth posune dál, některé body přestanou platit, proto je na několika místech napsané, ať si to Claude ověří přímo v repozitáři. A ještě jedno upozornění: aplikaci jsem zkoušel na emulátoru a na svém telefonu, ne na desítkách zařízení. Když se u vás něco rozbije, je to na vás.
Další díly
Ušetřil vám tenhle návod odpoledne hledání? Můžete mi koupit kafe. Nic za to nedostanete, port je zadarmo a prompt taky, ale potěší to.
Tohle byla víkendová zábava, ale stejně řeším i práci: rozchodit něco, co oficiálně nejde, nebo dát dohromady systém, který nikdo neprodává. Potřebujete něco podobného?
Napište mi