Snipes ported to C/C++ with 100% logic compatibility and replay recording

Getting old DOS games working. (DOSBox topics belong in DOSBox areas below, not here).

Snipes ported to C/C++ with 100% logic compatibility and replay recording

Postby Deadcode » 2016-7-22 @ 03:32

[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:

  1. 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.
  2. 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.
  3. 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).
  4. 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:
Image
And here's a screenshot from the same replay, with "omniview" (view of the entire maze at once) enabled:
Image

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:
  1. 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.
  2. 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.
  3. 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.
  4. 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:
  1. How was it originally packaged? I've seen four versions of it:
    1. 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.
    2. A single snipec.com file, which I made myself in 1997 by combining the Color overlays with the boostrapper.
    3. 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.
    4. 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?
  2. 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?
  3. 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.
  4. Was the 1982 version ever packaged with Novell Netware, or was it only NLSNIPES that was?
  5. 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?
  6. 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).

(same replay as the screenshots above):
Image
Last edited by Deadcode on 2016-7-27 @ 23:34, edited 1 time in total.
Deadcode
Newbie
 
Posts: 4
Joined: 2016-7-22 @ 02:05

Re: Snipes ported to C/C++ with 100% logic compatibility and replay recording

Postby VileRancour » 2016-7-23 @ 08:37

Can't really answer any of your questions with certainty, but this is a fascinating project - hope it does get released.

About font aspect ratios for square cells... since maze sections are 8x6 characters, the only thing you'd need to do is to modify your font for a 3:4 aspect ratio. I don't know what you've used to edit your custom font, but in FontForge this is quite easily done by messing with the width/height metrics (changing the width is less fiddly; TrueType fonts are always sized by line height). Let me know if you want specifics.

On an original CGA the maze sections were passably close to square, since a character cell is ~5:6 on screen. I've never actually tried ConEmu, but if it can do custom ratios as you imply, this may be a perfect opportunity to test my Unicode CGA fonts with it ;)

As for the version of Snipes first used to test NetWare... well, the obvious conjecture is that it isn't the same as the later NLSNIPES available to us. And based on this cover scan I guess that at least the single-player version was sold separately for a period. (BTW, some sources give 1983 as the time Novell switched to IBM PC clients, rather than 1982.)
User avatar
VileRancour
Oldbie
 
Posts: 1550
Joined: 2003-5-14 @ 22:11
Location: 1-01-80 0:00a

Re: Snipes ported to C/C++ with 100% logic compatibility and replay recording

Postby Deadcode » 2016-7-23 @ 11:41

I used FontForge + Inkscape to do my edits so far :) I noticed it does have a way to do a transform on all selected characters. The tricky thing would be selecting the right characters. I'd have to stretch the characters that look okay stretched, and leave certain others unstretched (ones that have perfect squares or circles in them, for example). The font has a large selection of Unicode occupied, so this would take a while. If FontForge has a way to "Select all characters not in the OEM437 mapping and delete them" that would make things easier, but it'd make them easier still if it had a way to display the OEM437 mapping rather than forcing me to page through to the Unicode locations of the OEM437 characters. I couldn't find a way in FontForge to jump to a particular character by Unicode hexadecimal code. I suppose I could just compile from source and add the features I need. Ideally I wouldn't want to delete any characters, but rather divide the font into subsets, where each subset gets a particular transform, and I get to tweak the transforms until everything looks sufficiently good.

Lucida Console has an aspect ratio of exactly 1234:2048. The aspect ratio to make maze cells perfectly square is 3:4 (which at 40×25 results in a 6:5 screen aspect ratio). So that requires characters to be stretched 124.47% horizontally. This makes characters with square or circle elements in them very visibly non-square/non-circular, so would have to be done selectively.

The cool thing about ConEmu is that it lets you specify both a width to stretch the characters to, and a width for the character cells. In the screenshots above I did a compromise between those two things. I stretched the font 107.877% horizontally, and stretched the character cells 124.47% horizontally (making the maze cells perfectly square, and diagonal movement average to exactly 45 degrees). The problem is that line-drawing characters would then have gaps in them, but ConEmu solves that problem, too! It lets you specify a set of Unicode character code ranges which it treats graphically, extending line segments to be continuous (analogously to how it was done in text mode on MDA, EGA, VGA and later; as you explain on your web page, "displayed with an additional 9th column (either blank or a duplicate of the 8th, depending on the character)"). The default is "Pseudographics: 2013-25C4;". The range I specified is "Pseudographics: 2013-25B9;25BB-25C3;".

And for Omniview I used [Raster Fonts 8x12], and stretched the character cells to 9 (yielding the desired 3:4 character cell ratio), with "Pseudographics: 2013-218F;2194-25B9;25BB-25C3;".

ConEmu also has a feature "Enhance progressbars and scrollbars"; enabling this checkbox renders the dithered-solid-block characters (176-178 (0xB0-0xB2) in OEM437, 0x2591-0x2593 in Unicode; the game uses them for explosions) as shaded solid color, which is nice because dither-patterns do not look good scaled up. Ideally however, I would like it to render these as dither patterns at the pixel scale, to retain the character of the game better.

Regarding CGA: With CGA stretched to a 4:3 screen ratio, the character aspect ratio becomes (4/3):(40/25) = 5:6 indeed. This has two problems; it doesn't make the maze cells square, and it requires scaling from 320×200 to 1600×1200 or 3200×2400 to get an integer ratio; too big for a 1920×1080 monitor, but leaving a lot of empty space on a 2560×1600 or 3840×2160 monitor. The square-maze-cell aspect ratio is much nicer in this regard; 1920×1600 fits perfectly into my 2560×1600 monitor, and is an integer ratio. The other options are 960×800 and 2880×2400, and one of those actually fits into a 1920×1080 monitor. (Back when I used a CRT, dealing with this stuff was quite simple. I just adjusted the horizontal size of the scan area... which on my Sony CPD-1304 was done using a physical knob.)

Your font page is awesome. And it confirms what I remembered — that in EGA and VGA, 40×25 text mode was implemented by the BIOS using 9×14 or 9×16 characters. Is there a way to get DOSBox to use the 9×16 font instead of 8×16?

Regarding the cover scan: The problem is I don't know if this was the real cover for the game, or a drawing a fan did later. I've seen no evidence either way...

Edit: Here is my Snipes port with your PxPlus IBM VGA9 font:
Image

and PxPlus IBM CGA (looks pretty good, which shouldn't be surprising since the game was designed for it):
Image
Deadcode
Newbie
 
Posts: 4
Joined: 2016-7-22 @ 02:05

Re: Snipes ported to C/C++ with 100% logic compatibility and replay recording

Postby VileRancour » 2016-7-23 @ 17:16

Maybe this will help- I'm attaching my CP437 encoding files for FontForge, which you can import with 'Encoding->Load Encoding' (try the .ps first, if that doesn't work the .txt should). Then you could Reencode from Unicode to that, which would delete all characters not in the CP437 map. If you do want to keep the extra codepoints, you could save the above result to a new file, apply a separate metrics transform on each file to your liking, then 'Element->Merge Fonts' to get the desired mix of the two.

encoding_CP437_gfx.zip
(4.2 KiB) Downloaded 11 times

I don't know if it's that important to have perfectly circular snipes/ghosts, since the original didn't, but that's just a question of aesthetics ;)

Deadcode wrote:And it confirms what I remembered — that in EGA and VGA, 40×25 text mode was implemented by the BIOS using 9×14 or 9×16 characters. Is there a way to get DOSBox to use the 9×16 font instead of 8×16?

Both can do either 8- or 9-column chars, it's just that in EGA the default is 8 (possibly not modifiable outside of MDA-emulation mode), and in VGA it's 9. DOSBox will do 9x16 by default with "machine=vgaonly".
Come to think of it, you can then load a custom 12-line font and get 9x12, which would give you the 3:4 ratio you want if you also set "aspect=false"... the .F12 file here has one such font. I believe that recent DOSBox SVN revisions will let you modify the width in all VGA machine types by setting 9/8 Dot Mode (as on a real VGA) but I haven't tried that yet.

Nice work with those screenshots - although the VGA one does remind me why I've always disliked 40-column text on EGA/VGA (those horizontal / vertical stroke width ratios are ridiculous). :D But I guess there's always something to be said for experiencing things the way you originally did.

Also, you've pretty much convinced me now to try out ConEmu, so I'll be playing around with that for a bit, heh.
User avatar
VileRancour
Oldbie
 
Posts: 1550
Joined: 2003-5-14 @ 22:11
Location: 1-01-80 0:00a

Re: Snipes ported to C/C++ with 100% logic compatibility and replay recording

Postby Deadcode » 2016-7-27 @ 22:53

I got permission to release, from Drew Major and Kyle Powell! Here is the source code repository for my Snipes port:
https://github.com/Davidebyzero/Snipes

[Edited 2016-08-03: SDL / Linux port, and aspect-ratio-corrected TrueType font]

Thanks to help from my friend CyberShadow, Snipes can now be built under Linux, and any platform supported by SDL. Under Windows there's a choice of either console or SDL (the SDL build is much better).

Windows SDL build: either download Snipes.exe (and download SDL2 and SDL2_ttf if you don't already have them),
or download Snipes.exe with all dependencies included (SDL2, SDL2_ttf, SnipesConsole.ttf)

Here is my TrueType console font for Snipes: SnipesConsole.ttf
(no need to download this if you've already downloaded the Windows SDL build with all dependencies included)
I've corrected the aspect ratio of this font, to make maze cells and diagonal motion perfectly square, and also implemented nicely dithered 0xB0-B2 characters (0x2591-2593 in Unicode).
This font required for the SDL builds to run properly. By default, it needs to be in the current directory when Snipes is run. (For a different TrueType font to work well, some adjustments would need to be made to the source code.)

For Linux, build it from the source code on github, and put SnipesConsole.ttf in the same directory as the executable (or edit the config to the path where you put it before building). Installing https://aur.archlinux.org/packages/snipes-git/ will automate this process.

Windows console build: Snipes_console.exe
Due to the existence of the SDL build, and improvements to SnipesConsole.ttf, ConEmu instructions for the Windows console build are mostly obsolete, but here they are anyway:
Snipes.exe will run fine in the native Windows console, but to make it look best, ConEmu is probably the best option for now. Here is how to set it up:
  1. Install the TrueType font linked above.
  2. Install ConEmu; it can be downloaded from http://www.fosshub.com/ConEmu.html/
  3. Create a shortcut that executes: "drive:\path\to\ConEmu.exe" -config "Snipes" -run "drive:\path\to\Snipes.exe"
  4. Launch the shortcut
  5. Upon the first time launching ConEmu with that -config option, it will ask some questions. You can leave everything at default, but I change "Choose preferred color scheme:" to "<Standard VGA>". (You can change it again later if you like.)
  6. Right-click on the ConEmu titlebar, and click "Settings" in the context menu.
  7. Change "Main console font" to "Snipes Console". Set its Size, Width, and Cell. My settings to almost-fill my 2560×1600 desktop are Size=60, Width=39, Cell=45. To adapt this to a different desktop resolution, multiple all the numbers by the same ratio. (Unfortunately ConEmu only accepts integers, so round to the nearest.) (It is no longer necessary to set the Width and Cell; they can be left at zero, because SnipesConsole.ttf is now aspect ratio corrected.)
  8. In "Unicode ranges", enter "Pseudographics: 2013-25B9;25BB-25C3;". (It is now better to empty this field, disabling pseudographics.)
  9. In Main -> Size & Pos, set the Width and Height to 40 and 25, respectively. If they already say 40 and 25, you probably still need to update them; edit one of the boxes temporarily to activate the "Apply" button and then click it.
  10. In Main -> Appearance, make sure "Enhance progressbars and scrollbars" is checked. (It is now better to uncheck this, because SnipesConsole.ttf now implements the dithered-block characters nicely, which is more faithful to the original.)
  11. The color set can be adjusted in Features -> Colors. As stated above I recommend keeping it at "<Standard VGA>".
  12. Click the "Save settings" button. Make sure to click this after making any further changes that you want to keep. This will save to the "Snipes" profile, or whatever name you put in your shortcut after "-config".
  13. Enjoy playing Snipes.


Please share your .SnipesGame replay files. I plan on enhancing the file format (while keeping backwards compatibility), and making it give more descriptive default names to the files, but it's quite usable as it is now.

After enough people have shared replay files, I'll release some of my own, but I'd prefer not to exhibit undue influence on people's playing styles by posting them immediately. (There are some strategies that could be spoilers; I'd like to see what people come up with on their own.)

Anyone want to recommend some additional place(s) to post this?
Deadcode
Newbie
 
Posts: 4
Joined: 2016-7-22 @ 02:05

Re: Snipes ported to C/C++ with 100% logic compatibility and replay recording

Postby gerwin » 2016-10-31 @ 01:26

Thanks a lot Deadcode for making and sharing this Port! I missed the initial announcement, but found it when I was searching for a Snipes remake. So now DosBox is no longer required to play Snipes, and the graphics are slightly improved.

This weekend my 8 year old nephew saw me playing the original Snipes. Surprisingly, despite the primitive looks, he was curious about it. So next time he can have a go with this new port.

Since you asked for replays: attached is my replay of winning at a very ordinary skill H 7. This is the skill level I tend to prefer, without these purple ghosts.
The game was without an icon so I made a simple one, and attached it as well. You can use it if you want.

On the Windows XP system here there is a small problem with this SDL port often crashing at startup. I don't know why, it says something about ntdll.dll. But when set to Windows 95 compatibility the problem goes away. (The console version runs without such issues)
Attachments
Snipes_icon.zip
Snipes Icon 32x32
(253 Bytes) Downloaded 26 times
replay_H7.zip
Replay Snipes H-7
(919 Bytes) Downloaded 14 times
User avatar
gerwin
l33t
 
Posts: 2370
Joined: 2004-5-07 @ 19:21
Location: NL

Re: Snipes ported to C/C++ with 100% logic compatibility and replay recording

Postby Roosta » 2017-8-06 @ 03:32

Many thanks for the port. I built it from source and it works brilliantly on Trisquel.

Couple of questions:
Where can I find the key assignments (e.g. how to get 'omniview' mode)?
And has anyone a working implementation of the multi-player version?
Roosta
Newbie
 
Posts: 1
Joined: 2017-8-06 @ 03:16


Return to DOS

Who is online

Users browsing this forum: No registered users and 2 guests