Click here to Skip to main content
15,885,985 members
Articles / Game Development

Programming Nostalgia: revisiting Mike Wiering’s Mario Game Written in Pascal

Rate me:
Please Sign up or sign in to vote.
5.00/5 (6 votes)
11 May 2023CPOL8 min read 4.9K   5   4
Revisiting Mario Game Written in Pascal
In this post, I revisit Mike Wiering’s Mario game which was written in Pascal.

I have always been a fan of Super Mario game (and its variants) ever since the first time I touched the computer keyboard. I remember the first time playing it on my old 80386 computer and could not get past the canal in the middle of level 1:

Image 1

After I managed to get past the canal and proceeded to higher levels, it seemed that I could not get through level 4:

Image 2

I decided to give up and did not attempt the game until years later when I had an Internet connection at home and soon figured out that I was playing on an uncompleted version of the game. By then (around the year 2000), Mike Wiering, the original author of the Mario game for MS-DOS, had released the source code on his website. Unlike my version, which proceeds directly to level 1 upon startup, the full version supports 2 players (MARIO and LUIGI) and has a menu with some other options:

mariostartup

Compiling the Source

The game will not run on modern computers – it stopped at a black screen upon startup, perhaps due to some illegal VGA function calls. It also cannot run on Windows Vista and above, or 64-bit version of Windows, due to a lack of 16-bit compatibility as well as full-screen support. These days, DosBox is the only option if I want to play the game. Interestingly, this MARIO game, and similar games by Wiering Software such as Charlie II, Charlie the Duck or Super Angelo play fine on DosBox but seem to have timing issue (the speed is very fast) when run from inside a virtual machine such as Microsoft Virtual PC, VmWare or Sun VirtualBox.

With some Pascal programming knowledge and time at hand, I decided to have a closer look at the source code, to figure out how Pascal is used in game programming, and this article will discuss some interesting facts that I have found.

The first thing I learned was that the released executable was packed (as described in the README.TXT provided with the source code) to reduce file size to 57KB, perhaps with some MS-DOS packing utility. The compiled executable can be as big as several hundreds KB. In those days with 360KB floppy disk, this was probably a huge concern.

Source Code Organization

The source code is quite well organized into several Pascal unit files (*.PAS) and sprite include files (*.00?). Variables are well named and procedures are well structured. Although there are few inline comments provided since the code was never meant to be released to the public, the code can be understood and modified by anyone willing to do so.

The description of the main source code files can be found below:

  • MARIO.PAS: The main application
  • WORLDS.PAS: All level data are hard-coded here
  • BACKGR.PAS: Unit to support drawing the game background such as skylines
  • BLOCKS.PAS: Assists in the drawing of animation
  • BUFFERS.PAS: Support reading of level and sprite data into buffers
  • CPU286.PAS: Halt the program if a CPU older than 286 is detected
  • ENEMIES.PAS: Define Mario’s enemies, such as turtle, fish or moving objects
  • FIGURES.PAS: Define behavior of objects along MARIO’s way, except for enemies
  • GLITTER.PAS and TMPOBJ.PAS: Display glitters such as stars that show when Mario hits coins or an object
  • JOYSTICK.PAS: Support the use of a joystick
  • KEYBOARD.PAS: Process keyboard input
  • MUSIC.PAS: Play sound using PC speaker
  • PALETTES.PAS: The color palette used to draw the game
  • PLAY.PAS: Main game logic, e.g., how MARIO interacts with enemies, objects, earn coins, etc.
  • PLAYERS.PAS: Define the behavior of MARIO and LUJI.
  • STARS.PAS: Draw the stars on the sky
  • STATUS.PAS: The game status line
  • TXT.PAS: Text processing unit
  • VGA256.PAS: Custom Turbo Pascal VGA unit (Mode 13h, 320×200 256 colors)

Creating Sprites

Sprites are first created using GRED.EXE (see GRED.TXT included in the source code):

Image 4

It will be saved as a binary file (*.000, e.g.: TREE.000), and then exported to a Pascal file that looks like the following:

Image 5

The Pascal file is named TREE.$00. If a sprite has multiple states, as is the case for animated object, the extension is incremented, e.g., TREE.001 and TREE.$01. Sprites will be included as an include file in FIGURES.PAS:

Pascal
{$I Tree.$00} {$I Tree.$01} {$I Tree.$02} {$I Tree.$03}

The point here is to store all sprites and level information into the code section, not the data section, of the program. The data segment in Pascal program can only contain up to 64K of data, and the game may grow beyond that. If slow read speed (earlier games ran on floppy disk) and having the game in multiple files was not an issue, an alternative would have been to store the data as external file.

Code would then be written to access the disguised data stored in the code segment by means of procedures consisting entirely of DB directives. The following will draw TREE000 at the specified location:

Pascal
PutImage (XPos, YPos, W, H, TREE000^);

PutImage is defined in VGA256.PAS:

Pascal
procedure PutImage (XPos, YPos, Width, Height: Integer; var BitMap); 

Level Data

As mentioned in README.TXT, there is no level editor for this game. All levels are coded in WORLDS.PAS:

Image 6

A typical level consists of 2 procedures, a level data file (Level_1a) and an option file (Options_1a). Similar to sprites, they are just assembler procedures having only DB directives to store data. The option file will define how the level data will be interpreted. Take a look at Intro_0 and Options_0, for the ‘intro’ level, which is the background shown behind the selection menu:

Image 7Image 8

Each assembler directive defines each vertical portion of the screen. One DB is a string of 13 characters. Each character defines an object on the screen, from bottom to top. The character 0 marks the end of a level (e.g., DB 0). The same character may be interpreted differently in different levels if the level options are different – see function ReDraw() in FIGURES.PAS. All level data will be loaded into variable WorldMap (found in BUFFERS.PAS) using ReadWorld(). Some levels may have certain pipes where Mario can dive in to enter a different area – these are defined as sub levels, for example, see Level_1b.

A Modern Approach

With some free time at hand, I decided to try out and see how the level data can be re-used to display an overview of each level, without re-writing everything from scratch. My first task is to save the sprites as an image file, which was easy since the GRED file format is documented. It wasn’t long before I managed to write a tool in VB.NET that loads a sprite binary file and display in a PictureBox:

Image 9

All sprites will then be converted to VB.NET resources. The next challenge would be to export the level data. Based on function PlayWorld in WORLDS.PAS, I wrote my LVL2BIN.PAS which exports all level data to a binary file (*.LVL):

Image 10

It is used as follows:

Pascal
WriteLevelToBin(@Level_1a^, ‘Level1a.LVL’);

For the level options, to facilitate modifications, I did not export it to binary file, but instead convert to an XML file:

Image 11

Most of the code is available from function ReadWorld() in BUFFERS.PAS. I adapted them to VB.NET with some minor modifications to cater for zero-based array index in VB.NET (Pascal supports non-zero-based array) and the lack of set data types in VB.NET. For example, the following simple Pascal code:

Pascal
var Ch: Set of Char;

….

Ch = [C] + [#1 .. #13];

turns complicated and probably more expensive in VB.NET – a List has to be used to emulate a set:

VB.NET
Dim Ch As New List(Of Char)

Ch.Add(C)

For i As Integer = 1 To 13

If Not Ch.Contains(Chr(i)) Then Ch.Add(Chr(i))

Next

The following shows the level viewer in actions. it reads level data (.LVL) and options (.XML) and displays it on the screen:

(For simplicity, enemies and background are not yet drawn.)

When I was writing the code, there was something which surprised me. Despite the different look of the bricks between intro level (level 0) and level 2 (see image below), they actually come from the same sprite (BRICK0.000).

Image 13

The tricks are in the following two functions in FIGURES.PAS:

Pascal
procedure ReColor (P1, P2: Pointer; C: Byte);

procedure ReColor2 (P1, P2: Pointer; C1, C2: Byte);

Both were written in assembly:

Image 14

All that the seeming complicated assembler code above will do is to loop through every pixel in the image and modify its color by 1 (for ReColor) or 2 (for ReColor2) constants to make the new image look different. This allows the same image to be used for 2 different levels yet still look different. I converted both of them to VB.NET:

VB.NET
Private Function ReColor(ByVal fig As Bitmap, ByVal factor As Integer) As Bitmap

Private Function ReColor2(ByVal fig As Bitmap, _
ByVal factor1 As Integer, ByVal factor2 As Integer) As Bitmap

However, despite using the exact same constant and same color palette, my resulting display of level 2 does not look exactly the same:

Image 15

I am unable to locate the exact problem and can only assume it’s due to something I might have overlooked.

At this point, I can proceed to draw the background, animated sprites (turtles, fish, …) and implement the proper game if I want.

Easter Eggs

The game has some Easter eggs which can be found in PLAY.PAS. To activate cheat mode, press P to pause the game, then press TAB. Pressing 2305 while in cheat mode will get you through the next level. Also, if you prefer to play in grayscale, press MONO:

Image 16

Similar Games: Charlie the Duck, Charlie II and Super Angelo

According to Wiering Software, these three games are developed based on the original Mario source code; however, their source code was never released. Charlie II (my favorite game) also has a Windows version which was perhaps written in C++. As of 2011, it’s pretty clear that no future DOS versions of these games will ever be created, and any future version will perhaps only be in Flash. Click here and here if you want to try out.

I hope this article will be useful for those who want to port the game to other platforms, or to learn something about game development in Pascal.

The full .NET source code to convert sprites and view the levels can be downloaded here.

See Also

References

  1. Open Game Source: Mario Clone

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

 
GeneralMy vote of 5 Pin
Sam V 20235-Dec-23 21:04
Sam V 20235-Dec-23 21:04 
GeneralMy vote of 5 Pin
Sam V 20235-Dec-23 21:04
Sam V 20235-Dec-23 21:04 
GeneralRe: My vote of 5 Pin
CHill605-Dec-23 21:05
mveCHill605-Dec-23 21:05 
GeneralMy vote of 5 Pin
Sam V 20235-Dec-23 21:04
Sam V 20235-Dec-23 21:04 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.