Turbo Pascal 2.0 course cover
← Back to Courses
module
36

Finishing Touches

Introduction

The game works, and it is played in # and $. The Einstein can do better, and S26 showed how. This last piece gives the warehouse walls that look like brickwork, crates that look like crates, and a worker who looks like a person; and a title screen to greet whoever plays it.

Four Characters To A Picture

S26 redefined one character - eight rows of six dots. But a square of the warehouse is two characters wide and two high, so a picture that fills it is twelve dots by sixteen, and takes four characters: top left, top right, bottom left, bottom right. Here is the crate, with the four characters marked:

......|......
.#####|#####.
.#....|....#.
.#.###|###.#.
.#.##.|.##.#.
.#.#.#|#.#.#.
.#.#.#|#.#.#.
.#.#.#|#.#.#.
------+------
.#.#.#|#.#.#.
.#.#.#|#.#.#.
.#.##.|.##.#.
.#.###|###.#.
.#....|....#.
.#####|#####.
......|......
......|......

Each row of each character is a number, exactly as in S26, and the left character of a row takes its first six dots, the right one the next six.

Warehouse uses twenty characters, from 128 up, in fours:

CharactersPicturePattern
128-131a brick wallBrick
132-135a crateBox
136-139a crate on its goal - filled inFull
140-143a goal - a spotSpot
144-147the workerWorker

One Define For Four Characters

The four characters of a picture are next to each other in the font, and the font is eight bytes a character, one after another in the video chip's memory. So character 132's eight bytes are followed at once by 133's, then 134's and 135's - and since the chip moves on by one after every byte it is given (S26), one address and 32 bytes define all four.

That is all Define needs to change: the address of the first character, and a Pattern of 32 bytes instead of eight:

procedure Define(First: Integer;
                 Shape: Pattern);
var
  A, I: Integer;
begin
  A := $1800 + First * 8;
  Port[9] := A mod 256;
  Port[9] := A div 256 + $40;
  for I := 0 to 31 do
    Port[8] := Shape[I];
end;

Each pattern is written as four rows of eight numbers - top left, top right, bottom left, bottom right.

Two Strings Per Square

Then the game needs only its constants changed. Top and Bot hold each tile's two halves as characters instead of # and $ - and a string of characters with no printable form is written as their codes one after another: #128#129 is the two-character string of character 128 then character 129.

Everything else - Show, the editor, Where - already draws through Top, Bot, ManTop and ManBot, so the whole game changes at once. That is the pay-off of drawing every square in one place.

The characters must be defined before anything is drawn with them, so the five Defines are the first thing the program does. The editor's keys stay #, $, ., * and @ - they are keys, not pictures, and they are what a level plan is written in.

A Title

Title clears the screen, shows the pictures with what each one is - Item draws a picture's two halves and a word beside it - says how to play, and asks for a level:

Read(Kbd, Ch);
N := Ord(Ch) - Ord('0');

The digit keys have codes one after another, so a digit's code minus the code of '0' is its value. A key that is not a level number gives level 1. (One key means at most nine levels can be chosen here; the game plays any number.)

The Code

Start WARE from WARE9: W WARE, E, CTRL-K CTRL-R, WARE9.

In the type part, after Level's end;:

  Pattern = array[0..31] of Byte;

In the second const part, Top, Bot, ManTop and ManBot become as below, and the five patterns follow them:

  Top: array[Tile] of Str2 =
    (#128#129, '  ', #140#141,
     #132#133, #136#137);
  Bot: array[Tile] of Str2 =
    (#130#131, '  ', #142#143,
     #134#135, #138#139);
  ManTop: Str2 = #144#145;
  ManBot: Str2 = #146#147;
  Brick: Pattern = (
    $FC,$04,$04,$FC,$20,$20,$FC,$04,
    $FC,$00,$00,$FC,$20,$20,$FC,$00,
    $04,$FC,$20,$20,$FC,$04,$04,$FC,
    $00,$FC,$20,$20,$FC,$00,$00,$FC);
  Box: Pattern = (
    $00,$7C,$40,$5C,$58,$54,$54,$54,
    $00,$F8,$08,$E8,$68,$A8,$A8,$A8,
    $54,$54,$58,$5C,$40,$7C,$00,$00,
    $A8,$A8,$68,$E8,$08,$F8,$00,$00);
  Full: Pattern = (
    $00,$7C,$7C,$70,$68,$64,$64,$64,
    $00,$F8,$F8,$38,$58,$98,$98,$98,
    $64,$64,$68,$70,$7C,$7C,$00,$00,
    $98,$98,$58,$38,$F8,$F8,$00,$00);
  Spot: Pattern = (
    $00,$00,$00,$00,$00,$04,$0C,$1C,
    $00,$00,$00,$00,$00,$80,$C0,$E0,
    $1C,$0C,$04,$00,$00,$00,$00,$00,
    $E0,$C0,$80,$00,$00,$00,$00,$00);
  Worker: Pattern = (
    $00,$04,$0C,$0C,$04,$1C,$2C,$2C,
    $00,$80,$C0,$C0,$80,$E0,$D0,$D0,
    $2C,$0C,$08,$08,$08,$18,$00,$00,
    $D0,$C0,$40,$40,$40,$60,$00,$00);

Before MakeLevel, the new Define:

procedure Define(First: Integer;
                 Shape: Pattern);
var
  A, I: Integer;
begin
  A := $1800 + First * 8;
  Port[9] := A mod 256;
  Port[9] := A div 256 + $40;
  for I := 0 to 31 do
    Port[8] := Shape[I];
end;

After Won, the title:

procedure Item(Y: Integer; A, B: Str2;
               S: Str20);
begin
  GotoXY(10, Y);
  Write(A);
  GotoXY(10, Y + 1);
  Write(B);
  GotoXY(14, Y);
  Write(S);
end;

procedure Title;
begin
  ClrScr;
  GotoXY(16, 2);
  Write('WAREHOUSE');
  Item(5, ManTop, ManBot, 'You');
  Item(8, Top[Crate], Bot[Crate],
       'A crate');
  Item(11, Top[Goal], Bot[Goal],
       'A goal');
  Item(14, Top[Stored], Bot[Stored],
       'A crate on its goal');
  GotoXY(5, 18);
  Write('Push each crate to a goal.');
  GotoXY(5, 19);
  Write('You can push but not pull.');
  GotoXY(5, 22);
  Write('Level, 1 to ', Total, '?');
  Read(Kbd, Ch);
  N := Ord(Ch) - Ord('0');
  if (N < 1) or (N > Total) then
    N := 1;
end;

And the main program's first lines become:

begin
  Define(128, Brick);
  Define(132, Box);
  Define(136, Full);
  Define(140, Spot);
  Define(144, Worker);
  Undo := nil;
  OpenFile;
  Title;
  Start;

Title sets N, so the N := 1; line goes.

Starting from

WARE9 from S35, read into a new work file WARE. Make the changes, CTRL-K CTRL-D, S, R. The patterns are long: check each number against the listing before you run it - a wrong one gives a wrong dot, not an error.

What you should see

The title, with the game's own pictures in it:

The title screen

Press 1, and the first level in brickwork:

The first level in the game's own pictures

Everything else plays as before - undo, W, the editor, the best scores.

Change One Thing

  • Change the Worker pattern to $20,$24,$2C,$2C,$14,$0C,$0C,$0C, $10,$90,$D0,$D0,$A0,$C0,$C0,$C0, $0C,$0C,$08,$08,$08,$18,$00,$00, $C0,$C0,$40,$40,$40,$60,$00,$00. What is the worker doing now?
  • Take out the five Define lines. Restart the Einstein, start Turbo, and run the game. What has happened to the walls - and the crates?
  • Change Define(132, Box) to Define(132, Full). Can you still tell which crates are home?

Exercises

36.1 Design a crate of your own, on squared paper twelve dots by sixteen first, and put it in Box.

36.2 Show each level's best score on the title screen, down the right hand side.

36.3 Make Level complete! flash five times before it stays.

Worked solutions are in Appendix II.

When It Goes Wrong

SymptomCause
Walls, crates and the worker are a scatter of strange shapesThe characters were never defined - the Define lines are missing, or come after the drawing - so the Einstein's own characters 128 to 147 appear instead.
A picture is scrambled, its quarters in the wrong placesIts pattern's four rows are in the wrong order: top left, top right, bottom left, bottom right.
One dot is wrongA mistyped number in a pattern. Draw that row out in dots, as in S26, and check.
Two pictures have swapped halvesA Define starts at the wrong character, or Top and Bot name the wrong ones. Each picture's four characters are next to each other, and each picture starts four characters after the one before.
Letters in the menu look odd after the gameA Define used a code below 128. Restart the Einstein.
Pressing a level number gives level 1The number is more than the levels in the file, or the key was not a digit.

Summary

Each picture is twelve dots by sixteen: four characters next to each other in the font, defined by one Define of 32 bytes. Top and Bot hold each tile's halves as #n#n strings, so changing them changes the whole game. Title introduces it and turns a digit key into a level number. This is Warehouse, finished.

Next

S37, A Program That Stands On Its Own - compiling Warehouse into a .COM file that runs without Turbo.

Get the Newsletter

New guides, disk images and community finds, roughly once a quarter. No spam, we promise, this isn't Tatung's marketing department.
Your subscription could not be saved. Please try again.
Your subscription has been successful.

Newsletter

Subscribe to our newsletter and stay updated.