This is the story of an adventure game I created around 1992 with my friend Alex. The game was never finished but the code is still on my hard drive. Every year it is getting harder to revive old code so I decided to make it run on Windows 10 and document some of its features.

Salou, the game that never was.

In 1990, I was a student at the Technisch Lyceum in Eindhoven. In 1989, the school had opened a new department called Technische Computerkunde, an offspring of Electrotechniek, which I had chosen to study. My love for computers started in the early eighties and the choice to switch to Technische Computerkunde was an easy one.

After learning about Voltage, Currents, Power, Resistance and even using my own body as a resistor by accident, I suddenly learned about the 8086 CPU, the OSI model, Unix and my new programming language for the years to come: Turbo Pascal.

It was Turbo Pascal 6.0 which I used to write my first real game. A game that never saw the light of day. It was called Salou and it was a graphical point-and-click adventure game.

disco

The game was not born out of a clear idea. Instead, it was born out of the boss-key.

Boss key

One of my classroom mates (Mike) created a Tetris clone for DOS. It featured crispy clear Hercules graphics and everyone in the class was addicted to it. Sometimes you walked into the classroom and there were at least 10 computer screens next to each other, all showing Mike’s Tetris game.

In fact, the game was so popular, that the teachers had to punish the students who were playing it during school because it started to mess with the school curriculum.

So we did what programmers do. We find solutions for problems. Tetris for DOS soon had a boss-key. This is a key that you press when you hear the door open behind you. Pressing the key makes the game go away in milliseconds! The first boss-key in Mike’s Tetris replaced the game screen with a beautiful fake Word-Perfect screen that was indistinquishable from the original Word-Perfect.

But after a while, it became suspicious when 10 screens in the classroom had the exact same Word Perfect screen when the teacher enters the room. So variations started to enter Tetris. The Borland Turbo Pascal IDE was one of them. Including some interesting code to show to the teacher. And it was all running inside Mike’s Tetris.

Fake DOS prompt

One of the boss-key screens was created by my best friend Alex and me. A fake DOS prompt. First we just created a prompt that answered to all commands with sentences like: “Nah, I don’t want to.” or “That doesn’t seem to work!”

We were heavily inspired by Maniac Mansion and loved the humor in the game. Very soon we created a language processor that responded to common DOS commands with all kinds of nonsense answers. We even let people login to their Novell account, only to tell them they should be careful not to type in their login and password at any blinking prompt!

It was the language processor that gave me the idea to create a text-based adventure, hidden in the fake DOS propt, hidden in the Tetris game. But Alex dreamt bigger! He wanted to create a graphical adventure, like Maniac Mansion. And not in someone elses game, we would create our own game!

At first, I thought that would be impossible. Or at least too much work. But as always, you just have to begin with the first step and go from there to get to the goal.

Salou, Spain

And the goal is in Spain. It’s 1989 and in the game, we drive with five friends from Eindhoven to Salou!

map

Step one: Choosing a graphics mode

It is hard to believe in 2021 but in 1992 (around the time we started with the game), games were made for specific graphics modes and sound cards. Making games on the PC was very barbaric compared to creating a game on a C64 or Amiga, where the hardware was unified and created with games in mind.

We chose VGA, With a 320x200 pixel resolution. Each pixel is represented by a byte and allows for 256 colors.

Here is a picture from the game in 320x200 pixels. On retina screens, it is hardly larger than a stamp :-)

beach

Here is the same picture, scaled up 8 times without resampling. It shows the individual pixels clearly:

beach

Step two: Choose a bitmap format

We needed a format to store the images. We looked at BMP but BMP was not compressed and with the many images we needed, the game would not fit on a single floppy disk. We wanted a format with basic compression in it.

The idea: If the picture has 100 pixels of red, then 50 pixels of yellow and then 25 green pixels next to each other, we write:

100A50B25C

The character codes for A, B and C would represent a color value from 0 to 255.

Step 3: Create a bitmap authoring tool

We needed a program to draw pixels and started working on a tool called LOOXEL. The name comes from LOOK, AXEL and PIXEL. To create a rectange of 100 pixels in the first version, we needed to click 100 pixels. We soon found out that was too much work and we needed a solution to draw pixellated lines and rectangles.

Alex and I both used a C64 in the eighties and loved Koala Painter.

beach

We could also have used an existing bitmap editor and compress the saved files but the thought did not even occur to us back then :-)

We took some ideas from Koala Painter and added lines and rectangles to LOOXEL. When an image was done, it was saved with the compression strategy I showed earlier.

With lines and rectangles added to the tool, pictures like the city map where easy to draw:

map

Also pictures with lots of the same color where easy to make:

boat

The final thing we added to LOOXEL was copying regions. This made pictures with repeating tiles very easy to create:

store

Turbo Pascal

Most of the code was written in Turbo Pascal 6.0

store

Turbo Pascal was originally developed by Anders Hejlsberg and it came with a fantastic IDE. Many of its great features later showed up in Delphi and Visual Studio.

Here is some typical code from the game:

Procedure DeurOC;
Begin
  If Buffer('OPEN DOOR') Then
  Begin
    If Status[Statu]=0 Then Comment('THIS DOOR IS LOCKED.','',5,'');
    If Status[Statu]=1 Then Stat(Statu,2,'IT@S OPEN.','',true);
  End;
  If Buffer('CLOSE INSIDE') Then
  Begin
    If Status[Statu]<2 Then Comment('THIS DOOR IS ALREADY CLOSED.','',5,'');
    If Status[Statu]=2 Then Stat(Statu,1,'IT@S CLOSED.','',true);
  End;
  If (Voorwerp1='DOOR') And (Status[Statu]=2) Then Voorwerp1:='INSIDE';
End;

Procedure Pool;
  Begin
    Delay(5000);
    Fu;F1:=54;
    Loopy(94,90);
    YY:=90;finaly:=90;
    Delay(5000);
    Comment('THERE@S SOMETHING BLINKING ON THE BOTTOM','',5,'');
    Delay(20000);
    LoopY(0,66);
    YY:=66;finaly:=66;
    WelkePop:=5;
  End;

We certainly did not care about naming conventions in this game.

Display bitmap

Showing the bitmap on the screen in a for-loop was too slow for the game. Even if we used pascal to write directly to the video memory, we could see the pixels appearing on the screen. We needed help to improve this. One of our classmates (Stijn) came up with the solution: “Why not use assembly in turbo pascal?”.

We learned about one of the most cool features of Turbo Pascal. By replacing the BEGIN keyword by ASM, we could execute a block of assembly code. And still interoperate with pascal variables. This was pure magic and looks like this:

Procedure Beeld(Welpop:Boolean);
Begin
  ASM                     { Stukske machinetaal zet plaatje op het scherm }
    XOR  DI,DI
    MOV  AX,0A140h        { beginadres plaatje }
    MOV  ES,AX
    MOV  SI,Offset F_Inh.Pic
    MOV  CX,44800
    CLD
    REP  MOVSB
  END;
End;

Notice the F_Inh label that accesses the F_Inh variable, defined in Pascal:

TYPE deFileInh          = ARRAY[1..140,1..320] OF byte;
VAR  F_Inh              : deFIleInh;

Here is an example of the fast loading and displaying of the bitmap using assembly in pascal, when I enter a building:

open door

Even on an 80286 this worked without flickering or delays.

Language processing

In 1992 we had no idea about the math behind language processing. We wanted to create something like the SCUMM engine and created a very naive system to combine:

VERB ITEM (WITH) (ITEM)

Here you see a simple example with a VERB and an ITEM:

buy stuff

All the mouse position checking is done by comparing mouse coordinates against hot spots in the game. Appearantly the function Oja does this. Oja in dutch means something like: “Yeah? We’ll see about that”. Again, our naming strategy could be better.

Procedure BWinkel; {401}
Begin
  Oja(-01,033,128,150,010,080,'OUTSIDE',8);
  Oja(000,053,104,071,022,080,'CHIPS PAPRIKOS',8);
  Oja(000,073,104,091,022,080,'CHIPS NATURELLOS',8);
  Oja(108,053,390,072,100,080,'LIMONADA',8);
  Oja(196,073,322,091,124,080,'MELONS',8);

  If GOT('PESETAS') <> 0 Then
  Begin
    If Buffer('BUY CHIPS PAPRIKOS') OR buffer('BUY CHIPS NATURELLOS') Then Comment('NO! IT@S GOLDEN WONDER!','',5,'');
    If Buffer('BUY LIMONADA')       OR buffer('BUY WATER') Then Comment('I@M NOT THISTY!','',5,'');
  End;
End;

Function CheckOut(Woordje:String) : Boolean;
Begin
  CheckOut:=False;
  If CS='CHECKOUT '+Woordje Then CheckOut:=True;
End;

Function Ab(V1,V2:String):Boolean;
Begin
  Ab:=False;
  If (CS='USE '+V1+' WITH '+V2) Or
  (CS='USE '+V2+' WITH '+V1) Then Ab:=True;
End;

Combine items

The game also allows combining items. Here I use money to buy cola from the vending machine:

asm

If (BufferUse('PESETAS','KAS COLA MACHINE')) Then
  If Got('CAN OF KAS COLA')=0 Then AddInv('CAN OF KAS COLA','MY FAVORITE!','',False)
Else Comment('YEP, I@VE GOT SOME ALREADY','',5,'');

Procedure AddInv(What,C1,C2 : String;PlaatjeZetten:Boolean);
  Var Teller,EersteLege : Integer;
  Begin
    FoutCS:=False;
    EersteLege:=0;
    For Teller:=1 to MaxInv Do
    Begin
      If It[Teller].Naam=What Then Exit;
      If It[Teller].Status=0 Then
      Begin
        EersteLege:=Teller;
        Teller:=MaxInv;
      End;
    End;
.
.
.

Dialog

It is also possible to interact with people in the game. Let’s order a sandwich at cafetaria TUFTUF!

dialog

antw(14,'WOULD@NT YOU RATHER HAVE SOME PATATAS...');antw2(14,'...OTHERWISE I HAVE TO TURN ON THE TOASTER');
while eruit1=false do
begin
  showmouse;Gm;
  if (mousex>232) and (mousex<354) and (mousey>58) and (mousey<103) and (mousebuttons=leftbutton) then begin tostie;
  eruit1:=true; end;
  if (mousex>112) and (mousex<232) and (mousey>58) and (mousey<103) and (mousebuttons=leftbutton) then eruit1:=true;
end;

Sea animation

To make the sea more lively, the horizon has some pixel animation going on:

sea

This is done by writing random pixels at row 78 directly to the screen memory. But only if the current color is between 51 and 55 which is a shade of blue:

Procedure Sea;
Var Rnd:Integer;
Begin
  Rnd:=Random(320);
  If  (Mem[$A000:(Rnd+(78*320))] > 51)
  And (Mem[$A000:(Rnd+(78*320))] < 55)
  OR (Mem[$A000:(Rnd+(78*320))] = 11)
  Then Mem[$A000:(Rnd+(78*320))] :=Random(3)+52;
End;

Puzzles

The game contains many puzzles. One of them is trying to avoid the entrance guard. If he catches you, you are thrown off the property!

sea

There are many more puzzle and most of them are based on things we experienced in 1989/1990 when our group of friends went on our holidays in Spain. The goal of the game is to find the girl, but not before you:

Find the shiny object at the bottom of the pool

Comment('THERE@S SOMETHING BLINKING ON THE BOTTOM','',5,'');

blinking

Find out what these stacked bottles are for

bottles

if (mousex>435) and (mousex<462) and (mousey>89) and (mousey<112) and (tt.vw[11]<1) then voorwerp:='STICK';
if (mousex>216) and (mousex<366) and (mousey>48) and (mousey<112) then voorwerp:='TENT';
if (mousex>378) and (mousex<436) and (mousey>89) and (mousey<112) and (tt.vw[11]<1) then voorwerp:='BOTTLES OF HENNINGER';
if (mousex>378) and (mousex<470) and (mousey>96) and (mousey<112) and (tt.vw[11]>0) then
voorwerp:='BROKEN BOTTLES OF HENNINGER';

Try out where the crack in the wall leads

wall

Could the secret entrance be behind this Opel Kadett?

opel

What’s the story about the secret boat at the horizon?

secret

How does it end?

We had a lot of fun creating “Salou”. But as always, you get to a point where you have to finish and polish something to make it really good. And both Alex and I had other things to do.

In 1993 I was drafted in the Army and could not work on the game for a year. After that we sporadically worked on the game but lost our joy doing so. I guess we both found other things to do.

By 1994 we knew the game was never going to be finished and we archived the code. The last log entry is from june ‘94:

09-06-94 Increased Bar. 2 screens HIFI STEREO left and right
         Cafe Altstad has picture of zenyatta mondatta

Conclusion

This week (March 2021) I installed DOSBOX and to my surprise, the code still works on an iMac, running Windows 10. Computer technology changes fast and I have learned that if you have projects from the past that you are proud of, you should archive it well.

Render music to mp3, render graphic designs to simple bitmaps and make screencasts of software you created. There is no guarantee you can run the software needed to revive old projects in the future!

The game taught me that no amount of work is too much if you just start and go from there. Working with someone who has the same humor helps of course.

Even if the game was unfinished, the lessons learned still help me to create games for Windows 10 in 2021.

Written by Loek van den Ouweland on 2021-03-05.
Questions regarding this artice? You can send them to the address below.