First post, by Deadcode
[Edit: I have released the port.]
I first played Snipes sometime around 1988-1990, when I was 10-12. Snipes was enigmatic to me, having no documentation at all, not even a title screen, and its terse credits, "Snipes (C)Copyright SuperSet Software Corp. Orem, Utah 1982", were only in the executable image, not printed when running it. I had to discover the keys and game mechanics through trial and error. IIRC, some time passed before I discovered that the squares generated snipes, and significant time passed before I discovered that holding the spacebar made movement fast.
This game always impressed me. It's quite entertaining despite running at just 40×25 character text mode, and it's ahead of its time, giving an identical gaming experience regardless of the speed of the PC it's run on. When I first played it (on my 4.77 MHz PC XT with EGA), I was impressed by its speed and smooth scrolling, and how it was one of the few programs I had at the time that, mysteriously, managed to be able to read multiple keys held at once (at that early time I programmed only in BASIC, and couldn't do either of these things).
Over the years I have occasionally revisited Snipes. It started to become legendary that I had never been able to beat it at level Z9. So for the past couple months or so I had some extended sessions of playing it under DOSBox, trying to beat Z9. Eventually I started regularly getting really close, often destroying 9 out of 10 generators before losing. I also researched its origins; for this, Tribute to text-mode games - Snipes and an article it links to, Novell and the computer game that changed networking, was especially instrumental.
Then in an intensive 4-day hacking session, I disassembled and ported the original Snipes executable to C (manually "decompiled" it, because I couldn't find a decompiler for 16-bit x86 code), resulting in a version of it that runs as a Windows console app (Linux support should be easy to add) with precisely the same game logic, "graphics", and sound as the original, and with replay recording/playback functionality added. The motivation for this project was:
- I really wanted my first time beating Z9 to be recorded, and not just in video (which is much larger than necessary, and doesn't retain any record of the user input and internal logic that resulted in what is seen and heard; so for example, it can't be played back with a full view of the entire maze at once). The last time I tried JPCRR (April 2013, when I made a 63 second tool-assisted run of beating level Z9) it was incredibly slow, much slower than real-time even when emulating a 4.77 MHz XT, and impressed me with how generally poorly designed it is, so that was not an option.
- I wanted to open the door to doing a tool-assisted run with lots of randomness manipulation, which would require brute-forcing the best random seed for a maze that puts the 10 generators within close access of each other and the player's initial position. With only 65536 possible initial seeds (based on the 18.2 Hz timer), this is actually quite attainable.
- Merely patching the game executable was not an attractive option, because of the limitations of 16-bit code and DOS, and the inability to make it display the entire 128 by 120 characters of the maze at once (for tool-assisted play).
- I wanted to learn about the game's internals, including the meaning of skill levels A-Z and 1-9 and how the snipes' AI works. (I still have further work to do in this area.)
Since then I have been cleaning up the code more and more, including a bit of C++. All of the functions and most of the variables are now named.
I also made a patched version of DOS snipes to playback replays, to verify that I achieved 100% identical game logic; it turned out that I hadn't quite (see below where I list bugs found in the original game's code; it's the last one). After rectifying this, both my port and the DOS version play my replay files in perfect sync.
I have also made a TrueType console font for Snipes, based upon Lucida Console, with key characters improved to look better: so far, one of the player bullet frames (to match the other one), the diagonal snipe bullets, and the snipes themselves. I would like to make it even better, by giving it an aspect ratio that results in square maze cells (without any need to enable a special stretching option e.g. in ConEmu, as seen in the screenshot below), but that'll be significantly harder. It might be better just to make the game render itself graphically, with sprites designed to be scalable but faithful to the original look.
Here is a screenshot of my port, running under ConEmu:
And here's a screenshot from the same replay, with "omniview" (view of the entire maze at once) enabled:
One of the upshots of this project was that I discovered a secret skill-level-based option that apparently nobody was aware of. Letters W through Z make the generators partially invulnerable to snipe bullets (whereas in A-V generators are 100% vulnerable), with a 39.0625% chance of being destroyed when hit (see below for further details). I'll gladly make a full chart of the effects of A-Z and 1-9 if anybody is interested. One of the things I was curious about was if every letter is unique, and if every number is unique; the answer is yes to both.
In the course of this project I have found 3 bugs in the code of the 1982 game:
- If a snipe comes out of a generator that is flush against the right side of the maze, it will wrap incorrectly, skipping one character on its way out. This is only a latent bug and can never occur in the actual game, because generators are always centered in maze cells.
- When a player bullet destroys a generator, the player has only a 60.9375% chance of scoring, depending on the animation frame of the generator. There are 16 frames in this animation, 8 of which are identical to each other (invisible); the other 8 are each a unique color. When hitting the upper-left corner of a generator, the chance is 9/16, and when hitting any other corner, the chance is 10/16.
- Likewise, in skill levels letters W-Z, a snipe bullet hitting a generator has a 60.9375% chance of not destroying it. I'm pretty sure the chance of non-destruction was meant to be 100% in this case. It would make beating Z9 even harder.
- This is the most interesting bug. It is in fact a bug in the PL/M-86 compiler! One procedure call doesn't have a "PUSH CX / POP CX" pair surrounding it, and thus overwrites the CX register with the wrong contents. The result is that when a ghost has the opportunity to bite the player, but doesn't (a random choice), it then moves in a way other than what was intended.
I would like to release this port, and ideally its source code on git as well. But this situation seems rather unprecedented to me. I'm not sure if anybody has ever fully ported a game by reverse-engineering it, keeping 100% identical logic. (Edit: For game engines, I know there is precedent, like Infocom Z-Machine, Scumm, etc.) Should I get permission from its original SuperSet Software authors, or at least Drew Major, first?
There is of course further work to be done, including finding all the differences between the Monochrome and Color versions, and between the 1982 version (written in PL/M-86) and NLSNIPES (compiled with a 1991 version of Borland C++ — does that mean it was ported to C, or was it reimplemented in C from scratch?) However, having played both the monochrome version and NLSNIPES under DOSBox, I think the 1982 color version is by far superior. The aspect ratio is just totally wrong in the other two versions, and the game mechanics and lack of color are less entertaining, and even annoying. And I'm not sure if this is by design or due to a problem running it under DOSBox, but NLSNIPES has enormous lag in responding to keyboard input. (And to make sure I earned the right to criticize NLSNIPES, I kept playing it at its maximum difficulty level of 9 until I beat it, which took over an hour. It was hard, but nowhere near as hard as beating the color version at Z9.) (Note: I got it to run under DOSBox by un-PKLITE'ing it and patching two bytes to make it skip the lock() loop during initialization.)
I'd also like to know more about the game's origins, including:
- How was it originally packaged? I've seen four versions of it:
- The one I was originally given back in 1988: a tiny snipe.com bootstrapper with four overlay files, two for Color mode and two for Monochrome mode; it has no title screen, merely asking for skill level at startup. This is the version that Snipes enhanced for VGA patches.
- A single snipec.com file, which I made myself in 1997 by combining the Color overlays with the boostrapper.
- An "IGREC" version, which I downloaded in 1999. Like #2 it is a single snipes.com file. However, this one takes the initial skill level as a command-line parameter rather than prompting for it, and changes back to 80×25 upon quitting the game.
- The "snipes.exe" — in fact a .com file, like #2 and #3 — hosted on textmodegames.com, which actually has a title screen that includes the message "broken by Randy". Does this mean it had some kind of copy protection originally? Was the title screen part of the original, or did Randy add it in?
- How was the original single-player 1982 version distributed/sold? Was it associated with Novell at all? Was it written before or after SuperSet Software got their assignment at Novell?
- Is it really true that Snipes was written to test the network? This statement is really suspicious, because of the huge time gap between the single-player 1982 version and the 1991-or-layer NLSNIPES.
- Was the 1982 version ever packaged with Novell Netware, or was it only NLSNIPES that was?
- How early was the multiplayer capability added? Were there earlier versions of it, besides the NLSNIPES.EXE that we have now? Did the original authors of Snipes have any involvement in making the multiplayer version?
- Who is Matt Brooks, seen in the string "Modified by: Matt Brooks" in NLSNIPES.EXE? Was he the one who added the multiplayer, working from the original authors' source code, or did he merely patch the executable unofficially?
One more note: At the time I completed the Snipes port to full logic-identical status with replay recording, I still hadn't yet beaten Z9 non-tool-assisted. But now I have! It was an exciting 10 minute run. I'd love to see what other people can do (releasing my port would of course help greatly with this, due to the replay recording).