Skip to content
PORTSNATIVE.
HomeCatalog
Web GamesEmulatorsToolsNews
PORTSNATIVE.

A catalog for discovering ports and related projects. We link to official sources and do not host original game files.

ExploreCatalogMy list
InformationAbout usSuggest a portSupportDonationsLegal notice
© 2026 PortsNative
Back to catalog
Total Annihilation (TA: Byte Tactics)
PORTSNATIVE

Total Annihilation (TA: Byte Tactics)

NATIVE PORTSTRATEGY / RTSWINDOWSALPHA

Total Annihilation (TA: Byte Tactics)

Total Annihilation

TechnologyNative C/C++ port (engine reimplementation)

Available forWindows

View official project

About the project

Total Annihilation es un videojuego de estrategia en tiempo real para PC de ambientación futurista, creado en 1997 por Chris Taylor y Cavedog Entertainment. Fue el primer videojuego de este género en implementar gráficos 3D en las unidades y el terreno, un paso muy significativo en una época en que las tarjetas gráficas con aceleración 3D aún no eran comunes.

Official project information

Author's original READMEOpen on GitHub ↗
<p align="center"> <img src="docs/images/banner.jpg" alt="Total Annihilation: Byte Tactics" width="100%"> </p> <p align="center"> <b>Every function of Total Annihilation, rebuilt in C++ and compiled back to the exact bytes Cavedog shipped.</b> </p> <p align="center"> <a href="https://github.com/HectorBailey/byte-tactics/actions/workflows/build.yml"><img src="https://github.com/HectorBailey/byte-tactics/actions/workflows/build.yml/badge.svg?branch=main" alt="Build from source"></a> <a href="#building-the-exe"><img src="https://img.shields.io/badge/TotalA.exe_MD5-8e74a1dffa1f5988624c52048f5b20cd-brightgreen" alt="TotalA.exe MD5 8e74a1dffa1f5988624c52048f5b20cd"></a> </p> <p align="center"> <a href="https://discord.gg/MDU9T5wZY">Join the Byte Tactics Discord</a> </p> <p align="center"> <a href="#progress">Progress</a> · <a href="#next-steps">Next steps</a> · <a href="#quick-start">Quick start</a> · <a href="#building-the-exe">Building the exe</a> · <a href="#how-a-match-works">How a match works</a> · <a href="#the-target">The target</a> · <a href="#contributing">Contributing</a> · <a href="#legal-and-licence">Legal</a> </p>

What is this?

TA: Byte Tactics is a matching decompilation of Total Annihilation (Cavedog, 1997). The C++ in src/ is written to compile, with the original Visual C++ 5.0 compiler, into machine code that is byte-for-byte identical to the game's own TotalA.exe. No approximations: if a function is marked matched, the compiler's output and Cavedog's output are the same bytes.

The matching is complete: all 3,267 game functions match, and the whole exe builds from source to the shipped bytes. The work now is making that source easy to read (next steps).

No game files and no Microsoft software are included. You bring your own copy of Total Annihilation; the setup script fetches the compiler for you.

<!-- progress:start -->

Progress

100.00% of Cavedog's code matched (850,853 of 850,853 bytes)

[########################################]

FunctionsBytes
Matched byte-for-byte3,267850,853
Attempted, not yet matching00
Not attempted yet00

By function size

The size bands are the size: labels on the issues.

SizeFunctions matchedBytes matchedBytes left
small (1 to 64 bytes)1,155 of 1,155100.0%0##########
medium (65 to 160 bytes)827 of 827100.0%0##########
large (161 to 400 bytes)703 of 703100.0%0##########
xl (401 to 600 bytes)226 of 226100.0%0##########
xxl (601 to 1,000 bytes)195 of 195100.0%0##########
huge (over 1,000 bytes)161 of 161100.0%0##########

By area

The linker kept each part of the engine roughly together, so each 64 KB of the executable is mostly one subsystem. The area names are guesses from the strings and Windows calls each window's code uses (data/areas.csv).

AddressesAreaFunctions matchedBytes matchedBytes left
0x400000Unit orders and unit AI210 of 210100.0%0##########
0x410000Orders and VTOL states222 of 222100.0%0##########
0x420000Frontend shell154 of 154100.0%0##########
0x430000Maps, missions, briefings228 of 228100.0%0##########
0x440000Multiplayer setup246 of 246100.0%0##########
0x450000Options and audio menus176 of 176100.0%0##########
0x460000Game and skirmish setup, unit classes212 of 212100.0%0##########
0x470000Campaign and skirmish screens, resource bars259 of 259100.0%0##########
0x480000Unit definitions, COB scripting, TNT map264 of 264100.0%0##########
0x490000Config and registry, skirmish summary193 of 193100.0%0##########
0x4a0000GUI layout and GAF201 of 201100.0%0##########
0x4b0000UI controls and file packages314 of 314100.0%0##########
0x4c0000TDF parser, CD audio, string handles298 of 298100.0%0##########
0x4d0000Compression (SQSH), CRT/STL, debug, file I/O197 of 197100.0%0##########
0x4e0000Process exit, psapi93 of 93100.0%0##########

Generated by uv run tools/progress.py; per-function status is in data/progress.csv.

<!-- progress:end --> <!-- cleanup:start -->

Cleanup progress

The matching is done; this is how far the source has got toward reading like source.

Readability cleanup: about 73% of the way (mean of the rows with a target)

[#############################-----------]

Counts in src/ and include/ at origin/main, against e9367f13 (the roadmap's starting point).

StartNowTargetDone
Source files (.cpp)2,727276112, one per module (data/modules.csv)94%[###################-]
Placeholder functions FUN_<addr>1,0762810, named74%[###############-----]
Placeholder globals DAT_<addr>737620, named92%[##################--]
Placeholder classes Class_<addr>7696610, named14%[###-----------------]
Placeholder fields field_<offset>5893320, named44%[#########-----------]
Files that define Unit285571, one shared definition80%[################----]
Files opening with matching history30100, none100%[####################]
Casts ((T*)x)->1,6982170, casts the types allow87%[#################---]
Byte-offset access *(T*)(p + off) and (char*)p + off1,284370cases with no struct
Cleanup issues
Gather issues125 of 125 closed[####################]100%
Join issues34 of 34 closed[####################]100%
Name issues162 of 165 closed[####################]98%
<!-- cleanup:end -->

Next steps

Every function matches, but much of the code still reads like a decompiler's output: placeholder names such as FUN_004b4ba0 and DAT_0051e610, fields such as field_9b, parameters such as param_1, and one small file per function. The goal now is source that reads like a programmer wrote it, without changing a single byte of the exe (CI checks the MD5 on every change). The plan is in docs/tidy-up.md:

  1. Folders (done). Every file sits in a folder for its part of the game (src/units/, src/network/, src/map/ and so on) and is named after its module.
  2. Real names (mostly done). Functions, classes and globals take real names: Cavedog's own wherever the exe keeps them (HapiBank::OpenBank, the HAPINET_* functions, CMemoryCache), and otherwise names backed by evidence such as the strings a function uses. 2,359 of the 3,267 functions have one so far.
  3. Shared types and tidy files (next). Each file still declares its own view of the structures it uses. Next, every type gets one shared definition with named fields, the remaining functions, globals, fields and variables get readable names, and the one-function files are merged into one file per module.

Quick start

You need wine, 7z, cabextract, curl and uv.

tools/setup_toolchain.sh   # downloads VC++ 5.0 + SP3 into toolchain/, copies TotalA.exe from Steam

Set STEAM_TA if the game is not in the default Steam library. Then check that everything works:

uv run tools/check.py 0x401070      # should print MATCH

Building the exe

With the toolchain set up, the whole game builds from src/:

uv run tools/place.py            # build/place/TotalA.exe, compared byte for byte with orig/TotalA.exe
uv run tools/place.py --no-orig  # the same without reading the original exe
uv run tools/link.py --carve     # an ordinary LINK.EXE build, build/link/TotalA.exe

place.py compiles every source file with the original compiler and puts each function and each piece of data at its original address. The result is the shipped v3.1 exe, byte for byte:

MD5 8e74a1dffa1f5988624c52048f5b20cd
SHA-256 3b9c0fadabf3dc67ed5f05a70f1e1505a0c65deadd1a3c930adfe30e2a84995e

It takes about a minute on a fast machine. The one input that is not in the repository is Cavedog's art, the icon and the cursor: place.py takes them from orig/TotalA.exe, or from a folder given with --art DIR (or BT_ART_DIR) when the original is not there (the MD5 matches only with Cavedog's own). Without a copy of the game, BT_NO_ORIG=1 BT_NO_GHIDRA=1 tools/setup_toolchain.sh sets up the compiler alone.

link.py --carve links the same objects the ordinary way, so functions land wherever LINK.EXE puts them and the bytes differ, but that exe plays the game too (tools/playtest.py runs scripted games on both builds).

GitHub Actions builds the exe from source on every change to the code and fails unless its MD5 is the shipped one (.github/workflows/build.yml): the "Build from source" badge at the top shows the latest run on main, and each run's summary lists the MD5 and SHA-256 it built. docs/linking.md explains how both builds work.

How a match works

uv run tools/check.py 0x401070
  1. Finds the function's file (here src/game/economy.cpp, which defines UnitResources::Reset) and compiles it with /O2 /Ob2 /MT /Gz.
  2. Extracts the function from the object file.
  3. Compares it with the original, ignoring bytes the linker fills in.

It prints MATCH, or a similarity score and an assembly diff. The exit code is 0 only on an exact match.

tools/wcl runs cl.exe under Wine directly (BT_TOOLCHAIN=msvc5-rtm selects the unpatched compiler).

The target

TotalA.exe v3.1 patch, as shipped on Steam (see orig/TotalA.exe.sha256).

FactValueHow we know
CompilerVisual C++ 5.0 with Service Pack 3Linker 5.10; runtime library matches SP3, not RTM (tools/crtmatch.py)
Runtime libraryLIBCMT (static, multithreaded, /MT)568 LIBCMT code sections found byte-for-byte
Compiler flags/O2 /Ob2 /MT /Gz: automatic inlining, no C++ exception handling, __stdcall by defaultglobal std::vector initialisers need /Ob2; STL code only matches without /GX; 2308 of the 2387 game functions with stack arguments clean their own stack (#2290)
C++ libraryLIBCPMT (std::string internals, _Lockit, std exceptions)matched inside the game region; marked library
LanguageC++Source paths such as c:\cavedog\wargame\multi.cpp in the binary
Function map3,782 functions with exact start, size and argument countFPO debug records left in the exe
Link date1998-07-30PE header

Repository layout

PathWhat is in it
src/Reconstructed source, in folders by subsystem (docs/tidy-up.md); uv run tools/sources.py 0x401070 prints the file of a function
data/functions.csvEvery function in the exe (tools/functions.py)
data/modules.csvThe address ranges of the modules and their folders (tools/modules.py)
tools/Comparison and analysis scripts
docs/Technical guides, and the bugs found in Cavedog's code (docs/bugs.md)
orig/The original exe (ignored by git) and its expected hash
toolchain/VC++ 5.0 and the Wine prefix (ignored by git)

The function map

uv run tools/functions.py rebuilds data/functions.csv from the exe's FPO records, the runtime library matches and a call graph. Each function has a kind:

  • game: Cavedog code
  • library: runtime code, already matched
  • gap: no FPO record, likely hand-written assembly

Ghidra

tools/ghidra.sh (needs Java 21) loads the exe into Ghidra with that map, applies the struct layouts and signatures that matched source declares (tools/ghidratypes.py), and exports pseudo-C for every game function to build/ghidra/decomp/.

Contributing

The functions were handed out as GitHub issues labelled decomp, and coding agents (Claude Code, OpenCode, Codex) worked through them following AGENTS.md: claim an issue, decompile its functions in their own working copy, and open a pull request. To help, see CONTRIBUTING.md; docs/running-agents.md has more on running each tool.

Legal and licence

This is a preservation and research project. It is not affiliated with or endorsed by Cavedog Entertainment or Wargaming, who own Total Annihilation.

  • Tooling. The tooling in tools/ is MIT licensed (see LICENSE).
  • Game code. The reconstructed code in src/ is derived from Cavedog's work; we claim no rights over it and it is not offered under any licence.
  • Bugs. Bugs found in the original game are listed in docs/bugs.md.
Read official guide
CALIFICACIÓN
—
Loading votes…
Advertisement

PROJECT FILE

Project type
NATIVE PORT
Genre
Strategy / RTS
Status
alpha
Original platform
—
Technology
Native C/C++ port (engine reimplementation)
Version
—
Updated
—

Target platforms 1

Windows
View on GitHub
Advertisement