unciv: An Uncivilized File Extractor for Civilization: Call to Power

While writing up how to get the 1999 game Civilization: Call to Power running on modern systems, I wrote a simple tool to extract some of the graphics and other data from the game. In particular, it extracts the game's zfs archives, which contain the majority of the miscellaneous graphics (everything except tiles, sprites, and a few things like mouse cursors), as well as the sounds.

unciv also converts the game's rim graphics format to PNG, so you can look at lovely images like those on this page.

You can download unciv for x86 Linux or Windows, or look at the source code on GitHub.

Usage

Simply run:

./unciv.x86 <path to .zfs file>
A backdrop from CivCTP (tba000.rim)

Or, on Windows, drag-and-drop a .zfs file onto unciv.exe.

Some .zfs files you may find interesting include:

ctp_data/default/graphics/patterns/pat565.zfs
Background 'patterns' for various screens and dialog boxes.
ctp_data/default/graphics/pictures/pic565.zfs
Various pictures of units, wonders, and UI elements.
ctp_data/english/gamedata/gl/gl.zfs
Most of the text in the game.
ctp_data/english/sound/sound.zfs
Sounds with english dialogue.
ctp_data/default/sound/sound.zfs
Language-independent sounds.

You may notice that the structure of the ctp_data directory is very regular. In particular, language-specific data lives in a subdirectory (e.g. english) and the language-independent data in a parallel subdirectory, default.

Also, for graphics, there's usually both a 555 and 565 variant: these contain the same data, but encoded in a different format. 16-bit RGB graphics usually is in either 555 (5 bits each for Red, Green, and Blue) or 565 (where Green has 6 bits), and different graphics cards used different versions. Some games converted on the fly, but CivCTP clearly just stores both. unciv can convert both types of rim file, so it doesn't matter which you choose.

Source Code

unciv is written in Rust (indeed, save for some kernel patches, it's my first attempt at Rust), and it depends on the byteorder (v1.3+) and png (v0.15) crates. Note that png has an absolute boatload of dependencies of its own, so you'll need to get those (the 'cargo' utility, or 'apt' under Debian can get them all for you).

Compiling should be as simple as using:

cargo build

If you want unciv to correctly set the last-modified time of the files (mostly to 1999), you'll need to enable the set-timestamps feature, using:

cargo build --features set-timestamps
The set-timestamps feature requires the file_set_times unstable Rust feature. This requires a recent nightly build of the Rust compiler (and could break at any time)! Alternatively, if you're not afraid of blatantly ignorning Rust's best practices, you might be able to use a recent 'stable' compiler with the RUSTC_BOOTSTRAP=1 environment variable set. That's even more likely to break, and might make you feel guilty, though it worked here with Rust 1.69.

If you're using a Debian-based Linux distro, you can also build unciv using the distro packages. You'll need to install them:

sudo apt install rustc cargo librust-byteorder-dev librust-png+deflate-dev
You should be able to replace librust-png+deflate-dev with librust-png-dev, though the PNG images produced may be uncompressed. I haven't actually tried it myself, though, so good luck!

You'll also need to point cargo to the Debian Rust packages, or else it'll try to download them from the crates.io repository. It involves setting a source in the .config/config file, as described on the Debian wiki. You can then compile it as above (though set-timestamps is unlikely to work.

Onward!

I hope this is of some use to someone! It probably will work with the sequel game Call to Power Ⅱ, too, though I haven't tried it yet.