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.
The game was not born out of a clear idea. Instead, it was born out of the 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.
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.
And the goal is in Spain. It’s 1989 and in the game, we drive with five friends from Eindhoven to Salou!
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 :-)
Here is the same picture, scaled up 8 times without resampling. It shows the individual pixels clearly:
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.
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.
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:
Also pictures with lots of the same color where easy to make:
The final thing we added to LOOXEL was copying regions. This made pictures with repeating tiles very easy to create:
Most of the code was written in Turbo Pascal 6.0
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.
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:
Even on an 80286 this worked without flickering or delays.
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:
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;
The game also allows combining items. Here I use money to buy cola from the vending machine:
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; . . .
It is also possible to interact with people in the game. Let’s order a sandwich at cafetaria TUFTUF!
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;
To make the sea more lively, the horizon has some pixel animation going on:
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;
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!
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:
Comment('THERE@S SOMETHING BLINKING ON THE BOTTOM','',5,'');
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';
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
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.