Heroes of Might and Magic V (Android Port)
Heroes of Might and Magic V (Android Port) is a port of Heroes of Might and Magic V to Android with native touch controls and a Direct3D 9 to OpenGL ES bridge.
- Type: PC port
- Game: Heroes of Might and Magic V
- Runs on Android
- By phys-winner
- Latest release v0.3.2-dev, 2026-10-31
- Source: https://github.com/phys-winner/pc_decomp_homm5
README
pc_decomp_homm5
Heroes of Might and Magic V, Hammers of Fate and Tribes of the East on Android ARM64 through static x86 recompilation, with native touch controls and a Direct3D 9 to OpenGL ES bridge.
Current version: 0.3.2-dev. All three engines use ThinLTO; Tribes of the East also uses PGO. This is an experimental port for sideloading. The original game's menus, adventure maps, towns, battles, sound and saves run through a local Win32 compatibility host. The game and eight DLLs are translated from x86 to C ahead of time, then compiled into a separate native library for each edition with the Android NDK.
Supported original games
The build inputs are the Russian releases of the three games from Heroes of Might and Magic 5: Bundle on GOG. Use your own installed copies. Other languages, executable revisions and mods are not verified build inputs.
| Edition ID | Original version | Input manifest | Native library |
|---|---|---|---|
toe | Tribes of the East 3.1 | config/modules.json | libhomm5.so |
vanilla | Heroes V 1.6 | config/vanilla.modules.json | libhomm5_vanilla.so |
hof | Hammers of Fate 2.1 | config/hof.modules.json | libhomm5_hof.so |
The SHA-256 values of each required executable and DLL are pinned in these
manifests. The lifter verifies every input
before copying, unpacking or relocating it. The original installation is read
only; unpacked images and generated C go into ignored local directories.
The launcher provides separate game cards, processes, settings and saves. Existing
ToE paths remain compatible with earlier builds. Native patch contracts also pin
the edition-specific host mappings and required port features; APK packaging
requires all three patched libraries and resource overlays, including when
--skip-native is used.
Vanilla 1.6 and HoF 2.1 have device smoke coverage for profile creation, scenario loading, adventure maps and troop splitting. Original-binary ABI checks and host regression tests cover their adapted native entry points. Device gameplay coverage is recorded separately from successful generation and compilation.
The older games use ToE's widescreen anchor policy with their own window geometry. Their font scaling follows ToE's equal horizontal and vertical glyph scale. Legacy UI and town-music overrides are also installed as loose resources: expansion archives take precedence over a new base PAK. Packaging and CLI deployment verify that every loose resource exactly matches its reviewed override archive. Ubisoft tracking is disabled before the startup commands in all three editions.
Original EXE/DLL files, resource archives, music, videos, maps and saves are not
distributed in this repository. The town music XML resources are read
from the selected edition's original resource banks during packaging, checked
against its manifest in config/music/, and patched in a separate Android overlay.
Current capabilities and limits
- Original menus, profile creation, scenario loading, adventure maps, towns, battles, saving and loading have been exercised during development.
- Touch input supports selection, movement, camera gestures, tooltips, spell targeting, troop and artifact transfers, and the Android keyboard.
- Additional game settings control render scale, interface scale, frame limit, camera sensitivity, touch cursor offset and optional touch cursor display. The default frame limit is 60 FPS.
- LAN play has been tested between Android devices and between Android and the original PC game with ToE 3.1. Peers use the same original game version and data; those checks do not establish LAN coverage for the other editions. Network discovery depends on the local Wi-Fi network.
- The launcher accepts an installed game folder or a ZIP containing its files. It can convert DXT textures to ASTC/ETC2 and skip the intro videos.
- An optional launcher switch, off by default, applies the MMH5.5 New Creature
Framework patches to ToE 3.1 (1000 creature records, IDs up to 999; random maps skip creatures
without map objects): the
Originalgroup of NewCreatureFramework.yml. Enable it only for a mod that provides those creatures: without their files the game does not start. Vanilla and HoF are unaffected. - Every edition renders with OpenGL ES. The experimental DXVK (Vulkan/Turnip) renderer for ToE 3.1 is disabled in this build; see Renderers.
- ARM64 Android 8.0 or later and OpenGL ES 3.2 are required. The manifest targets API 28; this development package uses legacy external storage access.
- Native libraries and APK packaging support 16 KiB alignment. This does not establish testing on a device with 16 KiB memory pages.
- Campaign completion, every map, every GPU and every Android version have not been verified. Development test results are not a complete compatibility claim.
Renderers (Tribes of the East)
Every edition, ToE 3.1 included, renders with the port's own Direct3D 9 to OpenGL ES 3.2 renderer.
An experimental DXVK renderer for ToE (DXVK 2.4.1 on the system Vulkan driver, or
on a bundled Mesa Turnip driver on Adreno 6xx/7xx GPUs) is disabled for now: on
the tested Adreno 650 with Turnip the game started, but the screen stayed black
after the startup device reset. Its sources remain in the repository
(android/dxvk, android/host/d3d9_dxvk.c), but the launcher offers only
OpenGL ES, runs no graphics driver check and the APK carries no DXVK libraries.
Re-enabling it for development takes the dxvk/turnip modes in the
renderers of android/port.json (the launcher base then adds its Vulkan
probe), HOMM5_DXVK in android/host/d3d9_dxvk.c and
tools/build_game_apk.py --dxvk.
Build requirements
The current scripts build on Windows x64, without Gradle. Install:
| Tool | Version |
|---|---|
| Python | 3.13 used during development |
| Android SDK platform | platforms;android-37.0 (the APK targets SDK 37) |
| Android SDK Build Tools | build-tools;36.1.0 |
| Android NDK | 27.2.12479018 |
| JDK | 17 or later; 24.0.1 used during development |
| UPX | 5.2.1, for unpacking the private copy of fmod.dll |
The launcher is the shared port launcher base, a sibling project
(../launcher, or an android/launcher submodule, or the folder named by
PORT_LAUNCHER); tools/build_game_apk.py renders it into the package
org.homm5.port.launcher from the game's description in
android/port.json.
Python requirements are pinned in requirements.txt.
The needed source snapshots of pcrecomp, MojoShader, dlmalloc, astcenc and etcpak
are vendored in reference/; zlib sources support desktop regression tests.
Versions, origins and local adaptations are recorded in
dependencies.json and
THIRD_PARTY_NOTICES.md.
Keep the supplied MojoShader snapshot: a plain upstream checkout omits the
legacy shader fixes used by this port.
Build the APK
Run these commands from the repository root:
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install -r requirements.txt
$env:ANDROID_HOME = Join-Path $env:LOCALAPPDATA "Android\Sdk"
$env:ANDROID_NDK = Join-Path $env:ANDROID_HOME "ndk\27.2.12479018"
$env:JAVA_HOME = Read-Host "JDK installation directory"
$homm5Upx = Read-Host "Path to upx.exe"
Copy-Item port.example.json port.json
notepad port.json
Set game_directory to the ToE installation, and set
editions.vanilla.game_directory and editions.hof.game_directory to the base
game and Hammers of Fate installations. A combined base-game/HoF installation
can supply both paths, for example C:/Games/Heroes of Might and Magic V.
Absolute paths and
paths relative to the repository root are supported. Use forward slashes or
escaped backslashes in JSON. The example uses originals/tribes-of-the-east.
device is optional and is needed only for developer deployment tools.
The personal port.json and the entire originals/ directory stay outside Git.
The scripts resolve the SDK using ANDROID_SDK, ANDROID_HOME, then
ANDROID_SDK_ROOT, or the current account's usual Windows SDK location.
ANDROID_NDK overrides the pinned NDK under that SDK. Set JAVA_HOME explicitly.
Generate the modules for all three editions, then compile and package:
foreach ($homm5Edition in @("toe", "vanilla", "hof")) {
python -X utf8 tools/lift_homm5.py --edition $homm5Edition --upx $homm5Upx
if ($LASTEXITCODE -ne 0) { throw "Generation failed: $homm5Edition" }
}
python -X utf8 tools/call_protocol.py
python -X utf8 tools/x87_locals.py
python -X utf8 tools/build_game_apk.py --thinlto --no-pgo
Output: build/android-game/heroes-v.apk.
tools/build_dxvk.py stages the ToE DXVK renderer in build/dxvk. It downloads
nothing and rebuilds no DXVK source. It reuses the DXVK, adrenotools and Turnip
binaries built by the sibling ut3 port, checks each one against its hash in
dependencies.json, imports the needed DXVK Native headers
into reference/dxvk, and compiles android/dxvk into libh5dxvk.so. --ut3,
--dxvk-library, --turnip-runtime and --dxvk-headers select other locations.
Run it again after changing android/dxvk or android/host/dxvk_methods.h;
tools/generate_dxvk_bridge.py regenerates those tables from the pinned header.
The APK builder packages the stage only with --dxvk (the renderer is disabled
by default, see Renderers) and then refuses a
stale stage. The DXVK libraries add about 6 MB to the APK and 24 MB when installed.
Packaging requires XZ Utils 5.4+ for its ARM64 branch filter (XZ, PATH, or
Git for Windows' mingw64/bin/xz.exe). All three engines are stored as XZ
assets with 128 MiB independent chunks. The small bundled XZ Embedded decoder
unpacks only the selected engine in the background on its first start after
an update. Its size and SHA-256 are checked before an atomic rename from
.part; later starts reuse the completed copy in private app storage.
Allow about 131 MB for ToE or 220 MB for each legacy engine, plus the previous
copy while replacing it after an update. Compression changes APK size, not
the game engines, resources or their installed sizes.
Generation creates checked PE images and C sources under generated/ for ToE,
generated/vanilla/ for the base game and generated/hof/ for HoF. Function
catalogs use the matching edition directory, while the original ToE catalog
paths remain under config/. These are all local
build outputs. Compilation fingerprints sources, headers, compiler and flags
before reusing objects. The APK builder compiles the texture converter and Java
launcher, includes the prepared PE images and port overlays, aligns the APK and
signs it with a locally generated development key.
Native builds remap embedded source paths to repository-relative names.
The two analysis steps produce build/call-protocol/summary.json and x87.json
for ToE. Run them again after regenerating or repairing its lifted functions.
The legacy editions use their own generated code and ABI mappings; they do not
reuse ToE register or x87 analysis reports.
For lower memory use and fewer compilation workers:
foreach ($homm5Edition in @("toe", "vanilla", "hof")) {
python -X utf8 tools/build_android.py --edition $homm5Edition --shared --thinlto --no-pgo --jobs 4 --thinlto-jobs 2
if ($LASTEXITCODE -ne 0) { throw "Native build failed: $homm5Edition" }
}
python -X utf8 tools/build_game_apk.py --skip-native --thinlto --no-pgo
--no-pgo makes the documented build independent of local training profiles.
Profiles stay outside Git and belong to their original engine: ToE uses
build/pgo/homm5.profdata, Vanilla uses build/pgo-vanilla/homm5.profdata and HoF
uses build/pgo-hof/homm5.profdata. To use available edition-specific defaults:
python -X utf8 tools/build_game_apk.py --thinlto
For an individual native build, --pgo-use PATH selects another compatible LLVM
profile for that edition. Do not apply a ToE profile to the other engines.
Performance can differ between builds using profiles and the profile-independent
build above.
The signing key is created in build/android/debug.keystore. Keep your local key
if you want subsequent APKs to update the same installation. Another key requires
uninstalling the old package or signing with the original key. Keys and keystores
are excluded from Git.
Install and provide game resources
- Install your APK on an ARM64 Android device and open Heroes V.
- Grant file access when the launcher asks: Android 11 and later need
All files access; Android 8–10 ask for storage, and a permanently refused
permission opens the app's settings. Choose the game folder (a folder inside
or above it works too) or a ZIP. A folder holding several editions, for
example Vanilla + HoF, is assigned to each of them. A ZIP is unpacked once into
/sdcard/HeroesV/game,game-hoforgame-vanilla(or a folder you pick), keeping only the folders the game reads and checking every file; a combined Vanilla + HoF archive is unpacked once for both. An offline GOG installer EXE is not a game ZIP. - Vanilla 1.6 requires
bin/,data/andDataLS/, includingDataLS/p6-data.pak. HoF 2.1 requiresbina1/, basedata/anddataa1/; it does not use the VanillaDataLS/bank. ToE requiresbin/anddata/. - Texture conversion is optional and can take time and additional storage space.
- Start the game from the launcher; keep a separate copy of your original game files.
The launcher shows a card per edition with Play, or Return to the game
while it runs. Options: skip the opening videos (per edition, on by default),
the players for LAN over Tailscale/VPN, and New Creature Framework (ToE). On
GPUs without DXT textures it converts them to ASTC or ETC2, can undo that, or
delete the originals afterwards to save space (irreversible). Cleanup previews
and removes the map editor, installers, manuals and store files. About shows
the version, the GitHub page, the update check and the language (English or
Russian). Updating from 0.3.x keeps the chosen game folders, edition and
options; saves stay in /sdcard/HeroesV/userdata*. On Android 17 the launcher
asks for local-network access before the first start.
The main menu's Переключить игру opens an Android dialog with the installed games and Открыть лаунчер. Switching saves the current engine's profile and closes it before starting the selected game. The ordinary exit dialog keeps its original confirmation buttons.
The application ID is org.homm5.port.
| Edition | Developer resource copy | Prepared PE images | Settings, profiles and saves |
|---|---|---|---|
| ToE | /sdcard/HeroesV/game/ | /sdcard/HeroesV/lifted/ | /sdcard/HeroesV/userdata/ |
| Vanilla | /sdcard/HeroesV/game-vanilla/ | /sdcard/HeroesV/lifted-vanilla/ | /sdcard/HeroesV/userdata-vanilla/ |
| HoF | /sdcard/HeroesV/game-hof/ | /sdcard/HeroesV/lifted-hof/ | /sdcard/HeroesV/userdata-hof/ |
The launcher can also use another selected resource directory. Its writable
folders remain under /sdcard/HeroesV/, as listed above.
Optional installation through ADB:
python tools/build_game_apk.py --skip-native --thinlto --install
If several devices are connected, pass --serial SERIAL or set ANDROID_SERIAL
or HOMM5_SERIAL locally. No device identifier is included in the repository.
For the standalone developer executable, build and deploy the selected edition:
python tools/build_android.py --edition vanilla --no-pgo
python tools/deploy.py --edition vanilla --data --serial SERIAL
deploy.py defaults to toe; --edition hof selects HoF. It validates the
selected executable's mandatory patch receipt before any device operation and
again before uploading native code. --data copies only that edition's resource
banks and shared assets, then applies private profile, intro, music and UI
overrides. It never modifies the installed PC game. Omitting --data updates
the prepared PE images and executable only. The executable is uploaded through
a temporary file and renamed; no game is started automatically.
The script prints a launch command with explicit --game, --data and
--images arguments; use those arguments for legacy executables because the
bare executable's default paths are the historical ToE paths. Developer
executables use /data/local/tmp/homm5[-vanilla|-hof]/homm5-arm64; deployment
receipts are build/deploy-receipt[-vanilla|-hof].json.
Touch controls
| Gesture | Action |
|---|---|
| Tap | Original selection or contextual action |
| Double tap your hero or town | Open its screen |
| Drag the map | Move the camera |
| Two fingers | Move, zoom and rotate the camera |
| Two nearby fingers moving vertically together | Tilt the camera, including in battle |
| Brief simultaneous tap with three fingers on the field | Restore camera tilt and rotation; in battle, also restore its position |
| Hold an interface element | Show its tooltip |
| Swipe left or right on a scenario's hero, faction, bonus, team or player-state icon | Cycle through the scenario's allowed choices. The active icon stays highlighted with its name and tooltip; heroes also show their specialization description |
| While aiming in battle, rest a second finger | Show the details card of the creature under the first finger at once; lift the second finger to hide it and keep aiming. Lifting the first finger while the second rests gives no order |
| While aiming in battle, tap with a second finger | Show the details card until the first finger lifts (no order is given); each further second-finger tap switches once between the card and the creature's effects |
| Tap a portrait on the battle initiative bar, then tap it again | The first tap selects the portrait (it stays highlighted); the second shows the creature's details card, which stays open without holding; each further tap on the portrait switches between the card and the effects; a touch elsewhere closes it |
| Hold a map or town object, or the battle initiative bar | Show its tooltip and details card; each second-finger tap on a held initiative bar portrait switches its card once |
| Drag your active shooter onto an enemy in battle | Melee attack instead of a shot, like Ctrl+click on the PC |
| Brief simultaneous tap with two fingers on the adventure map | Stop the moving hero or cancel an aim |
| Double tap the minimap, or tap it with two fingers | Toggle the highlighting of objects, like holding Alt on the PC; the camera stays. A single tap on the minimap moves the camera after a short pause (0.4 s) |
| Swipe left or right across the spellbook | Next or previous page |
| Swipe up or down across the spellbook | Previous or next bookmark (school); the orcish book of ToE switches its page. A tap that misses a bookmark by a little takes the nearest one |
| Drag a stack during troop deployment | Move it between the field and the reserve slots; the dragged portrait stays centred under the finger |
| Hold a deployment reserve portrait and tap the reserve bar with a second finger | Split one creature into the next free reserve slot per tap. Hold the second finger on a destination slot to open the original army split dialog |
| Swipe from a dropdown, move to an item and release | Select that item; a second finger cancels |
| Swipe on a slider | Move its value from where it is; a tap or hold does not move it |
| Swipe a list | Scroll |
| Drag troops or artifacts | T |