Porting Arcade Volleyball to the SMS

Introduction

Arcade Volleyball is a simple volleyball game I remember playing when I was quite young on a DOS PC. According to its Wikipedia article, this game would have been a shareware at the time but it is now in the public domain. I'm not sure how well known this little game is, but for me, it's a classic!

Also thanks to Wikipedia, I learned that this was originally conceived for the Commodore 64, but was also available for Amiga. The latter was distributed on a floppy disk included with the Fall 1989 edition of the Compute!'s Amiga Resource magazine, as an executable accompanied with its source code.

Source code? This caught my attention! I really like having the (sadly rare) chance to look at the source code of games from my youth. And this one was coded in C, my favorite programming language!

As it happens, I recently worked on a few small projects for the Sega Master System programmed in the C language with the help of devkitSMS. So I immediately thought, why not port this game to the SMS? It should be a nice little week-end project! (and it was!)

DOS version

DOS version

Amiga version

Amiga version

My SMS version

My SMS version




Here is a video of this game in action:



Download

Version 1.0
April 20, 2021 (Tuesday)
Initial release:
  • For 1 or 2 players
  • Playable with standard controllers or Paddle (HPD-200 or equivalent)
  • Tested on a Japanese SMS and NTSC Megadrive (US)
File(s):
avb-1.0.zip (11.9 KB)

This project is also available on GitHub!
To request features, report issues or contribute, you may send me an email or use the GitHub repository:
https://github.com/raphnet/arcadevolleyball


The porting process

This is a very simple game and so was the porting process. Still, I tought that it could be interesting to write a bit about it.

1. Getting my hands on the source code

First I had to find the source code. The Wikipedia article mentioned that it was included on the cover disk of the Fall 1989 edition of Compute!'s Amiga Resource... Thankfully, this has been archived. I found it here:

http://amr.abime.net/issue_1231_coverdisks


2. A quick glance at the code

The game source code came as a single file, ArcadeVolleyball.c, containing about 1500 lines. I went through it quickly, not trying to understand the game logic in detail, but rather to spot the inputs (keyboard/joystick) and outputs (graphics, sprites, sound effects).

Main takeaways: The background is drawn programmatically (i.e. it's not an image or a tilemap) and the game uses 16x26 hardware sprites. The joystick button state is checked by accessing specific memory addresses, and the sounds effects are samples.


3. A first compile using stubs

Changes to the source code began here. I commented parts of the code that would not apply (loading sound effects from disk for instance) and added a few empty functions (stubs) to replace those that were missing (Amiga system functions for instance), or used macros to make some calls disappear completely. I also defined a few data types, for instance USHORT to mean uint16_t.

No big issues, after a couple of minutes the game could be complied.


4. Reimplementing inputs (keyboard, joystick)

Here is the original joystick code. Obviously reading those memory addresses has no meaning on the SMS!
void joystick(pl)
int pl;
{
 USHORT *joy[2] = {
  {(USHORT *)0xDFF00A},
  {(USHORT *)0xDFF00C}
 };
 USHORT *firereg = (USHORT *)0xBFE0FE;

 keymove[pl].right=0;
 keymove[pl].left=0;
 keymove[pl].up=0;
 if ((*joy[pl^jflag]&0x0002)==0) keymove[pl].left=-2;
 if ((*joy[pl^jflag]&0x0200)==0) keymove[pl].right=2;
 if ((*firereg&(0x40<<(pl^jflag)))==0) keymove[pl].up=1;
}
I rewrote the above to call SMS_getKeyStatus(). I also rewrote another function which was checking for the ESC key to end the game. (I mapped the SMS pause key to this).


5. Dealing with the different screen size

This game is designed for a resolution of 320x200 pixels. But on the SMS, the screen is only 256x192...

At first, I thought of modifying the core of the game to work within the smaller screen, but after looking at the docollisions() function, this did not seem like a very good idea. There are dozens of checks for hardcoded coordinates checking the player, ball, net, borders, and the ball velocity would also have to be changed... Chances are I would break something or alter the feel of the game without knowing it unless I know exactly what I was doing.

Here is a portion of that docollisions() function:
    if (i && tby>81 && tbx>127 && tbx<160) {
  if (tby>91) {
   if (tbx<148)
    bvelx=-abs(bvelx);
   else
    bvelx=abs(bvelx);
  }
  else
   if ((tbx>147 && 161-tbx>=polecol[91-tby]) ||
      (tbx<148 && tbx-133>=polecol[91-tby])) {
    if (bvely>0) {
     dx=tbx-145;
     if (dx<-5) bvelx=-abs(bvelx);
     if (dx>5) bvelx=abs(bvelx);
     bvely=-abs(bvely);
    }
    if (abs(bvelx)>32) bvelx=bvelx>>1;
    if (abs(bvely)>32) bvely=bvely>>1;
   }
Sure, I could understand everything if I really wanted to, but one must chose his battles. Besides, there was an easier way: Scaling the final coordinates.

The game loops checks where the objects are, handles movement, collisions, etc, and then simply instructs the hardware to display the sprites at new coordinates. Those coordinates are meant for a 320x200 screen. To scale them down to fit the SMS 256x192 screen, I do the equivalent of this:
	X_sms = X - X/4 - X/16;
	Y_sms = Y - Y/8;
With this, a point at the lower right screen coordinate (319,199) will correspond to point 219,174, well inside the SMS display. So I apply the above transformation before calling SMS_updateSpritePosition.

Collisions between the ball and the players remain functional, as well as collisions between the ball and the environment, provided that the background elements (net, borders) are drawn at the right places.


6. Extracting the sprites

On the Amiga, the game uses 6 hardware sprites of 16x26 each. Every game element (ball, players) is built from a pair of adjacent sprites, and therefore occupies 32x26. Image data for the sprites is hardcoded. For instance, here is the first part of the data for the first half of player 1:
USHORT chip AVSpriteData[20][56] = {
 /* lmanOneLeft */
 {0x0000,0x0000,
  0x001A,0x000F,
  0x00D1,0x002F,
  0x0103,0x02FF,
  0x04C7,0x033F,
  ...
The above goes on for a total of 20 sprites. There is also a series of calls to function SetRGB4 to setup the color palette. After learning a bit about how Amiga sprites work and having understood the sprite image data format above, as well as which hardware sprite uses which range of colors in the palette, I wrote a small program to output a PNG file (see extsprites.c in the source) from the hardcoded data:



Notice how the ball appears squashed? I think this is due to the non-square pixel size of the original 320x200 resolution.


7. Adaptation des sprites

So the original graphics are basically 32x26. As the SMS has 8x8 pixel sprites, this would require 4 adjacent sprites for each player. The SMS has a limit of 8 sprites per line, so whenever the ball would fall between the two players, some sprites would disappear...

Luckily, as that the SMS screen resolution is lower (256x192 instead of 320x200) the original sprites needs to be scaled down. I ended up using 9 SMS sprites (3x3 layout) for players, and 4 SMS sprites for the ball (2x2 layout). When the ball falls between the players, there are exactly 8 sprites per line. Perfect, no problem!

Here are my final graphics, after a few tweaks to correct the ratio (got get round balls) and many touch-ups, as scaling down pixel art automatically was, as it usually is, quite a disaster.


Here is a zoomed-in version with a grid delimiting the SMS 8x8 pixel tiles.



8. Sound effects

There are 3 sound effects in the Amiga game:
  1. Sound when hitting the ball.
  2. Sound when scoring.
  3. Sound when loosing a serve.
I could have used pcmenc to try to use the original Amiga sounds (samples) on the SMS, but I must admit that I do not like the original sounds so much.... (according to what I heard by looking at the Amiga game on Youtube)

Having grown up with the "inferior" DOS version, I think I have come to expect a shrill whistle-like sound when scoring, and a lower, error-like sound when loosing one's serve. Hitting the ball does not make sound in the DOS version. On Amiga there is strange sound that shifts in pitch according to the speed of the ball, but I'm not a fan of it. Sorry.

Anyway, I just went ahead and made sounds I liked using Deflemask, and used PSGlib to play them back.


9. My personal touch: Paddle support!

According to the Wikipedia page, this game was inspired by a variant of Pong... Playing with a Paddle is therefore highly appropriate! I added the necessary support, so this version of Arcade Volleyball can be played with one or two Sega HPD-200 paddles (or homemade equivalent).

Supported SMS paddle examples

Supported SMS paddle examples




10. Conclusion

There many other small changes and things I had to do, such as removing the Quit option from the menu, adjusting text location, drawing the background, etc, but I won't discuss those in details, it would be too boring.

Overall I think that the game works wells and feels exactly like I remember. I like the result, and I am very happy of having had the chance of making an SMS port for a game I remember playing fondly!