Loki logo

Loki games on modern Linux

The Games that Linux People Play

Background

Between 1999 and 2002, Loki Software released native Linux version of a small list of contemporary commercial games.

If you're too young and have not lived those glorious days, here is a backup of their old (now broken) website so that you could feel the thrill. The FAQ is of no help today, but if you want see how the birth of the modern Linux game industry looked like, don't be shy and check out ;)

The Linux of year 2000 is very different from the Linux we know today, and so it can be quite difficult to get such old binaries working well on modern systems. While the Linux kernel has maintained very good backwards compatibility, other parts of a Linux distribution have changed, from the X server to libraries glibc, libstdc++, and SDL.

The Problems

The dynamically-linked binaries segfault, or are missing important feature.

The Bad Ideas

Using the static binaries does work on modern systems, but is problematic as the libraries compiled into them are old and have bugs; for example:

Another popular solution is to use an old version of glibc such as 2.2.5. However all the other libraries linked by the game must also be compiled against an equally old (or older) version of glibc. This is the "traditional way" of running these old games, by using the infamous loki_compat_libs-1.5.tar.bz2 compilation. However, they're not up-to-date enough to support PulseAudio/PipeWire, or any of the more modern parts of the Linux graphics stack, so ultimately don't solve all of the problems.

The Solution

  1. The idea is to use a little shim that adds back functions required by the old dynamically-linked binaries.
    This way you still run a modern stack with a recent glibc, latest xorg/wayland, Mesa, ...

  2. elfhash will be used to rename symbols to prevent clashes with system libraries.

  3. SDL

    Games were often build against libSDL-1.1.so.0 which is both very old, and unavailable in modern distribution. But it is ABI compatible with libSDL-1.2.so.0 that was the main version of SDL used for a decade and that was updated to support newer systems. patchelf will be used to change the dependency to SDL 1.2.

    But the story doesn't end there. SDL 1.2 was superseded by SDL 2.0 back in 2014 (and, indeed, SDL 3.0 is currently being worked on in 2024). SDL 2.0 is much more suited to modern hardware and operating systems than SDL 1.2 ever was. Not only does it provide native support for newer APIs like Wayland and Pipewire, it also supports newer ways of handling fullscreen windows (without nasty resolution changes or breaking Alt+Tab) and provides a hardware-accelerated 2D API which is much better suited to modern GPUs.

    SDL2's API is, while reminiscent of SDL 1.2's, not compatible, and indeed lacks some features. Some sort of compatibility layer is needed to adapt the old API into the new one, and to restore or emulate the missing functionality. Fortunately, such a compatibility layer already exists: sdl12-compat. Most Linux distros ship sdl12-compat instead of the original SDL 1.2 library, so you're likely already using it.

  4. Sound

    Some games use the original sound system for Linux, OSS, that was superseded by ALSA in 2002. On modern Linux, there is no more a /dev/dsp device file.

    There is an elegant solution to this problem: osspd. It's a userspace daemon that emulate the OSS devices (/dev/dsp, /dev/adsp and /dev/mixer).

    In the end the pipeline looks like this (it's a lot of forwarding, but on modern machines, it won't be too noticeable) :

    game-binary -> /dev/dsp -> CUSE -> osspd -> ossp-padsp -> pulseaudio -> ALSA -> speakers/headphones

Thanks/Credits

Thanks to Ryan C. Gordon and Sam Lantinga, they both worked at Loki back in the days and still work today on tools (like the SDL) we can use to make & play games on Linux.

I must credit David Gow for his technical article that prompted me to do some research and replay those old games :-)

The Games

Assuming the games are patched to the latest available patches (and there are never going to be newer patches) then to run them use the following instructions. The dynamic binaries are used where available.

Don't forget to export one of those environment variables, to prevent your graphics driver to expose an outrageously long list of OpenGL extensions.

$ export MESA_EXTENSION_MAX_YEAR=2002       # Mesa
$ export __GL_ExtensionStringVersion=17700  # Nvidia

If you don't do that, some games (heretic2, kingpin, shogo, sin, sof) will crash on startup.

CIVILSATION: CALL TO POWER

Credits: https://davidgow.net/hacks/civctp.html

https://snapshot.debian.org/archive/debian/20070911T000000Z/pool/main/f/freetype1/libttf2_1.4pre.cvs20060210-1_i386.deb

Path the binary:

$ patchelf --replace-needed libSDL_mixer-1.0.so.0 libSDL_mixer-1.2.so.0 civctp.dynamic
$ patchelf --replace-needed libSDL-1.1.so.0 libSDL-1.2.so.0 civctp.dynamic
$ perl -pe 's/\x{E8}\x{F5}\x{96}\x{B6}\x{FF}\x{89}\x{C0}\x{89}\x{45}\x{FC}\x{8B}\x{43}\x{04}\x{3B}\x{45}\x{FC}\x{75}\x{05}\x{FF}\x{43}\x{08}\x{EB}\x{14}/\x{90}\x{90}\x{90}\x{90}\x{90}\x{90}\x{90}\x{90}\x{90}\x{90}\x{90}\x{90}\x{90}\x{90}\x{90}\x{90}\x{90}\x{90}\x{90}\x{90}\x{90}\x{90}\x{90}/' < civctp.dynamic > civctp.dynamic_tmp
$ perl -pe 's/\x{83}\x{7B}\x{08}\x{00}\x{7E}\x{05}\x{FF}\x{4B}\x{08}\x{EB}\x{15}/\x{90}\x{90}\x{90}\x{90}\x{90}\x{90}\x{90}\x{90}\x{90}\x{90}\x{90}/' < civctp.dynamic_tmp > civctp.dynamic

Run the game:

SDL12COMPAT_FAKE_CDROM_PATH=/path/to/soundtrack LD_LIBRARY_PATH=$(pwd) LD_PRELOAD=/path/to/lokishim.so ./civctp.dynamic

DESCENT 3

LD_PRELOAD=/path/to/lokishim.so ./descent3.dynamic

HEAVY GEAR II

https://snapshot.debian.org/archive/debian/20070911T000000Z/pool/main/f/freetype1/libttf2_1.4pre.cvs20060210-1_i386.deb
https://snapshot.debian.org/archive/debian/20090809T095029Z/pool/main/g/glib1.2/libglib1.2ldbl_1.2.10-20_i386.deb

Path the binary:

patchelf --replace-needed libSDL-1.1.so.0 libSDL-1.2.so.0 hg2stub

Run the game:

./hg2

HEAVY METAL: FAKK2

Unfortunately the binary is statically linked with an old SDL, so we are stuck with it and it's bugs.
It is recommended to use the pak4.pk3 file provided by Chunky Kibbles to fix a crashing problem during the game.

./fakk2 -w +set r_gldriver /usr/lib/i386-linux-gnu/libGL.so.1

HERETIC II

Unfortunately, even the "dynamic" binary is statically linked with an old SDL, so we are stuck with that version and it's bugs

Path the binary:

$ patchelf --remove-needed libesd.so.0 heretic2.dynamic

Run the game:

./heretic2.dynamic +set vid_ref glx +set gl_driver /usr/lib/i386-linux-gnu/libGL.so.1

HEROES OF MIGHT AND MAGIC 3

SDL12COMPAT_COMPATIBILITY_AUDIOCVT=1 LD_PRELOAD=/path/to/lokishim.so ./heroes3.dynamic

KOHAN: IMMORTAL SOVEREIGNS

LD_PRELOAD=/path/to/lokishim.so:libX11.so.6 ./kohan.dynamic

MindRover

TODO - Only static binaries on CD.

MYTH 2: SOULBLIGHTER

The folks at Project Magma took over maintenance and have continued to release binaries for Linux up to 2021, so the old Loki binaries aren't needed anymore

Postal Plus

TODO - Only static binary on CD.

A new native (SDL2 based) Linux version is available for free on Steam.

RAILROAD TYCOON II

Path the binary:

$ patchelf --replace-needed libSDL-1.1.so.0 libSDL-1.2.so.0 rt2.dynamic

Run the game:

SDL12COMPAT_FAKE_CDROM_PATH=/path/to/soundtrack LD_PRELOAD=libX11.so.6 ./rt2.dynamic

RUNE

Path the binary:

$ elfhash -f __dynamic_cast -t __dynloki_cast System/Core.so

Run the game:

./System/rune-bin -log

SID MEIER'S ALPHA CENTAURI

LD_PRELOAD=/path/to/lokishim.so ./smac.dynamic
LD_PRELOAD=/path/to/lokishim.so ./smacx.dynamic

SIMCITY 3000

Use this shim: https://github.com/twolife/sc3u-nptl

https://snapshot.debian.org/archive/debian/20060714T000000Z/pool/main/g/gcc-2.95/libstdc%2B%2B2.10-glibc2.2_2.95.4-27_i386.deb
TODO: libopenal-0.0.so

Path the binaries:

$ patchelf --replace-needed libSDL-1.1.so.0 libSDL-1.2.so.0 sc3u.dynamic
$ patchelf --replace-needed libSDL-1.1.so.0 libSDL-1.2.so.0 sc3bat.dynamic

Run the game:

LD_LIBRARY_PATH=$(pwd) LD_PRELOAD=/path/to/sc3u-nptl.so:libstdc++-libc6.2-2.so.3 ./sc3u.dynamic

SOLDIER OF FORTUNE

Path the binary:

$ elfhash -f sl_add -t sl_adx liboasnd.so
$ patchelf --replace-needed libSDL-1.1.so.0 libSDL-1.2.so.0 sof-bin

Run the game:

LD_PRELOAD=libX11.so.6 SDL12COMPAT_SYNC_TO_VBLANK=1 ./sof

Tribes 2

TODO - or not, masterserver have been down for years

UNREAL TOURNAMENT

OldUnreal took over maintenance of the Unreal Tournament code base after reaching an agreement with Epic Games in 2019. So the old Loki binaries have modern replacement and aren't needed anymore.

blurline.gif

Other games from the same era

In 2000-2001 Hyperion Entertainment did port and released 2 more games of interest, that suffers from the same problems as the Loki ones.

SHOGO: MOBILE ARMOR DIVISION

Path the binaries:

$ patchelf --replace-needed libSDL-1.1.so.0 libSDL-1.2.so.0 cdaudio.dll
$ patchelf --replace-needed libSDL-1.1.so.0 libSDL-1.2.so.0 client
$ patchelf --replace-needed libSDL-1.1.so.0 libSDL-1.2.so.0 shogolauncher

Run the game:

LD_PRELOAD=/path/to/lokishim.so ./shogo

It may run too fast on modern computers. Add "MaxFPS" "30" to the ~/.hyperion/Shogo/autoexec.cfg configuration file.

SIN

Path the binary:

$ patchelf --remove-needed libSDL-1.1.so.0 sin.exe

Run the game:

LD_PRELOAD=/path/to/lokishim.so ./sin.exe +set vid_ref gl +set gl_driver_lib /usr/lib/i386-linux-gnu/libGL.so.1