Rogue

rogue, or at least the oldest version I could find at the time on the Internet, did not compile on modern systems.

    $ make
    ...
    *** Parse error: Missing dependency operator (Makefile:134)
    $ gmake
    gcc -O3    -c -o mdport.o mdport.c
    gmake: gcc: No such file or directory
    gmake: *** [<builtin>: mdport.o] Error 127
    $ CC=egcc gmake
    gcc -O3    -c -o mdport.o mdport.c
    gmake: gcc: No such file or directory
    gmake: *** [<builtin>: mdport.o] Error 127
    $ gmake CC=egcc
    ...
    mdport.c:47:10: fatal error: utmpx.h: No such file or directory
       47 | #include <utmpx.h>
          |          ^~~~~~~~~
    compilation terminated.
    gmake: *** [<builtin>: mdport.o] Error 1

Some of this is due to the original code (circa 1980) and the rest from meddling wizards over the years. The failures will depend on the particular system; clang on Mac OS X 10.11--this was before the name was uglified to macOS--objected strongly to dubious string handling in rogue. That is, the program would be segfaulted from somewhere in the guts of a system string function.

rogue for all its faults, which are many, is notable for spawning the roguelike genre. rogue fails certain definitions of what constitutes a roguelike.

A program that does not compile, or one that is segfaulted with extreme prejudice is easy to test: success is a program that can actually be run. Thee changes will be mechanical--removing needless GNUisms from the Makefile, modernizing the function signatures, fiddling with buffer sizes until the segfaults go away. The potential for new bugs or errors from such mechanical changes is pretty low (but is not zero!) especially if the person doing the refactoring isn't hung-over, stressed out, or otherwise distracted. And it's hard to write additional tests for something that will not even compile.

    $ wc -l Makefile
         145 Makefile
    $ git co master
    Previous HEAD position was 4ed5869 import from rogue3.6.3-src.tar.gz
    Switched to branch 'master'
    $ wc -l Makefile
          72 Makefile

Half the number of lines, and now compatible with BSD make. Granted, I did toss support for aix, cygwin, interix, irix, and nmake: I have no means of testing on those platforms, and zero interest in supporting them.

Systems tend to accumulate complexity over time; some of that complexity might be good complexity--better error messages from C compilers come to mind--but the complexity can also be bad: Spolsky's bloat, bugs, support for long dead operating systems, etc. (Or observe how once simple messages from a few humans can evolve into perhaps too complicated systems of religions.)

Refactoring old code is a necessary first step, but by no means the last; rogue has a lot of bugs. There was a softlock where the game would loop forever trying to place an item into a too-small room. And a potential softlock should a player be braced on both sides by floating eyes. The game runs too quickly on modern systems for various animations to display. The random number generator (RNG) is buggy and cannot be used for coinflips. The field-of-view (FOV) code and its many interactions with traps, items, messages, and monsters was (and doubtless remains) a source of many bugs. The save-game state and portability layer added around 1999-2006 had bugs. Various changes I made introduced new bugs.

Most of the bugs were fairly easy to fix; the FOV code probably needs a rewrite. Some bugs must be fixed, such as the softlock placing an item into a already full room, or string handling that the system finds objectionable. Other bugs are debatable, and may be left as "historic behavior": the bad RNG, the ability to read scrolls while blind, etc. Obviously the original conditions of rogue cannot be reproduced--we are now some 40 plus more years into the computer revolution--but choices can be made whether to retain or change particular elements of gameplay.

The message system probably needs a rewrite; there is little need for a non-verbose messages option given that the game is generally no longer run over 300 baud modems (or 1200 if you were lucky--and how good was your phone line? I recall a modem being pretty spotty at one house whenever it rained a lot). Maybe better use of the one message line could be made, or the ability to pull up in-game a list of previous messages. Memory was pretty tight back in 1980, for better or worse.

Wizard mode remains a mess; for that I documented that it should not be compiled into a version of the game that is exposed to untrusted users. Maybe one of these years someone will improve the code.

The complexity of rogue has been reduced; a feature that would automatically kill the game should the system load be too high was removed. rogue's resource use on a modern system is minuscule, unlike in 1980. The ability to shell out during the game was removed; this improves the security by disallowing fork and exec on OpenBSD under pledge(2) and unveil(2). In 1980 the ability to shell out and use your single login line for something else was rather important. Not so much in these luxurious days of many tmux panes. Also, various structural macros were removed; these prevented the use of gindent or clang-format, which I consider essential to help surface Apple gotofail type indentation bugs.

The test code, of which there is too little, can be found under the util directory, and mostly involves isolating or tapping into various facets of the system to see how they behave. In a modern system some portions of the game might be broken out into libraries with a well defined API and test suite, but that would be more work.

https://thrig.me/src/rogue36.git

tags #rogue #roguelike #make #c

bphflog links

bphflog index

next: Yet More Testing