Click here to Skip to main content
16,016,306 members
Articles / Game Development

Playing Alley Cat, a Classic MS-DOS Game, From Your Web Browser

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
5 Apr 2023CPOL3 min read 7.2K   3  
How to play the classic MS-DOS game - Alley Cat - from your browser
In this post, you will see how to play "Alley Cat" from your web browser.

Last week, I explored gabonator’s Visual C++ and JavaScript port of Alley Cat, one of my favourite DOS games. The project, despite being apparently abandoned since 2014, is still exciting to me as I love the idea of being able to play classic MS-DOS games the modern way without having to start any emulator. The idea also reminds me of SDLPoP, another similar and still active project which develops an SDL version of Prince of Persia using mostly knowledge gained from the disassembly process.

In a nutshell, the author used The Interactive Disassembler (IDA) to generate the ASM code for the original Alley Cat executable and then used another tool to convert the assembly code to its C equivalent. Although the output is in C syntax, it is still cryptic as it still contains register-like variables and methods with hexadecimal names:

alleycat_asm

However, this is where things become interesting. Instead of spending time understanding the logic and rewriting the code in a more readable (and maintainable manner), the author implements a miniature 8086 emulator in C which can be used to run the converted code. Assembly instructions such as push and pop are also written as C methods:

asm_int

With this approach, there is no need to modify the converted code, except perhaps to fix places where the converter did not do a good job, mostly obscure jumps that cannot be automatically translated into C code. Graphics calls are then modified to update a centralized CGA frame buffer, declared as a bitmap, to be drawn on screen when necessary:

C++
CFrameBuffer()
{
	HDC hDC;
	BITMAPINFO bitmapinfo;
	hDC=CreateCompatibleDC(NULL);
	bitmapinfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
	bitmapinfo.bmiHeader.biWidth=Width;
	bitmapinfo.bmiHeader.biHeight=-Height; /* top-down */
	bitmapinfo.bmiHeader.biPlanes=1;
	bitmapinfo.bmiHeader.biBitCount=32;
	bitmapinfo.bmiHeader.biCompression=BI_RGB;
	bitmapinfo.bmiHeader.biSizeImage=0;
	bitmapinfo.bmiHeader.biClrUsed=256;
	bitmapinfo.bmiHeader.biClrImportant=256;
	m_pBuffer = NULL;
	m_ourbitmap=CreateDIBSection(hDC,&bitmapinfo,DIB_RGB_COLORS,&m_pBuffer,0,0);
	m_pDC=CreateCompatibleDC(NULL);
	m_Old=SelectObject(m_pDC,m_ourbitmap);
	DeleteDC(hDC);

	FillMemory(m_pBuffer, sizeof(DWORD)*Width*Height, 0xb0);
}

PC speaker functions are also converted to Visual C’s Beep() function. The ported C code also loads the original .EXE into memory to simulate how an .EXE file is loaded on MS-DOS. Using a similar approach, the code is then converted to JavaScript to be executed on a browser.

Unfortunately, although I tried hard to replicate the author’s progress, the provided C code is missing several important pieces. Several functions are present in the JavaScript port, but not in the C codes, which indicates that the uploads were most likely incomplete. The JavaScript port still works to show the intro screen (see this for a demo) but hangs afterwards since its development was never completed.

Although I do not have the time to continue with the project, I was impressed by the efforts spent in porting the intro screen to JavaScript. After all, the converted C functions are cryptic and do not have meaningful names. I however do not think that this is an efficient approach since the final C codes are simply assembly instructions converted to C and not maintainable. I decided to go with PCjs, a JavaScript based PC emulator, and build a PC XT image that can boot Alley Cat in a browser, ready to play in just a few seconds.

This can be done with just the following HTML code:

HTML
<body style="font-family: Helvetica, Arial, sans-serif; display: none">
 <div id="ibm5160" style="width: 50%; height: 50%;"></div>
 <script type="text/javascript">
 embedPCx86('ibm5160','machine.xml','components.xsl','{autoMount:{}}');

 setTimeout(function() {
 // document.getElementById('ibm5160').setAttribute("style", "width:50%");
 }, 500);

 setTimeout(function() {
 document.title = "Alley Cat in a web browser";
 document.body.style.display = "block";
 }, 5000);
 </script>

 <!-- <a href="#" onclick="javascript:savePC('ibm5160', 'pcx86.js')">Save Machine</a> -->
 </body>

And the following machine configuration file:

XML
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="machine.xsl"?>
<machine id="ibm5160" type="pcx86" 
border="1" pos="center" background="default">
	<name pos="center">Alley Cat in a web browser</name>
	<computer id="xt-cga-640k" name="IBM PC XT"/>
	<ram id="ramLow" addr="0x00000" test="false" size="0xa0000" 
     comment="0xa0000 (640Kb) size overrides SW1|ROM BIOS 
     memory test has been disabled"/>
	<rom id="romBIOS" addr="0xfe000" 
	size="0x2000" file="XTBIOS-REV1.json"/>
	<video ref="ibm-cga-keygrid.xml"/>
	<cpu id="cpu8088" model="8088" 
	pos="left" padLeft="8px" padBottom="8px">
	</cpu>
	<fdc id="fdcNEC" autoMount='{A: {name: "AlleyCat", 
     path: "alleycat.json"}}' pos="left">
	</fdc>
	<keyboard ref="us83-softkeys.xml"/>
	<chipset id="chipset" model="5160" sw1="01001001"/>
	<serial id="com1" adapter="1"/>
	<serial id="com2" adapter="2"/>
	<mouse serial="com2"/>

</machine>

Where alleycat.json is the bootable version of AlleyCat, converted to JSON using PCjs instructions. To hide the PC XT boot process, the HTML body is hidden at load and only made visible by JavaScript codes after a few seconds, after the machine has finished loading. With this, Alley Cat can load nicely in the browser after just a few seconds and the entire game is playable:

alleycat_browser

The same approach can be used to make other DOS games playable in the browser without much effort. For those you are interested, the above setup can be accessed via this link. The ported C++ and JavaScript codes can be downloaded here.

See Also

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Technical Writer
Singapore Singapore
Since 2008, ToughDev has been publishing technical sharing articles on a wide range of topics from software development to electronics design. Our interests include, but are not limited to, Android/iOS programming, VoIP products, embedded design using Arduino/PIC microcontrollers, reverse-engineering, retro-computing, and many others. We also perform product reviews, both on new and vintage products, and share our findings with the community. In addition, our team also develops customized software/hardware solutions highly adapted to suit your needs. Contact us for more information.

Comments and Discussions

 
-- There are no messages in this forum --