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.
- Sound wouldn't work, as OSS is deprecated and have been replaced 20 years ago.
C++ ABI incompatibility
A lot of these old games segfault very fast. This is due to a change in libgcc/libstdc++ that broke some binaries that where compiled with gcc 2.95 in an unusual way (like compiling C++ code with gcc instead of g++).
LinuxThreads vs NPTL
The GNU C library POSIX threads implementation changed from LinuxThreads to NPTL in glibc 2.3.2 (and newer). LinuxThreads wasn't POSIX compliant but some games relies on some "side-effects"/misfeatures from LinuxThreads to run properly.
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:
- Sound wouldn't work, as OSS is deprecated, and tools like padsp don't work with statically linked binaries.
- SDL using a low screen refresh rate with XFree 4.3 or newer.
- Some parts of the window would be translucent, due to changes in how alpha-transparency is handled between X protocol / server versions.
- Fullscreen and/or resolution changes were brittle or broken.
- Wayland support was absolutely non-existent, and some of the above issues were worse with XWayland.
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
-
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, ... elfhash will be used to rename symbols to prevent clashes with system libraries.
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 withlibSDL-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.
Sound
Some games (fakk2, heretic2, hg2, rune, sc3u, sof) 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.
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