
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.
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:
| Characters | Picture | Pattern |
|---|---|---|
| 128-131 | a brick wall | Brick |
| 132-135 | a crate | Box |
| 136-139 | a crate on its goal - filled in | Full |
| 140-143 | a goal - a spot | Spot |
| 144-147 | the worker | Worker |
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.
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.
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.)
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:

Press 1, and the first level in brickwork:

Everything else plays as before - undo, W, the editor, the best scores.
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?Define lines. Restart the Einstein, start Turbo, and run the game. What has happened to the walls - and the crates?Define(132, Box) to Define(132, Full). Can you still tell which crates are home?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.
| Symptom | Cause |
|---|---|
| Walls, crates and the worker are a scatter of strange shapes | The 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 places | Its pattern's four rows are in the wrong order: top left, top right, bottom left, bottom right. |
| One dot is wrong | A mistyped number in a pattern. Draw that row out in dots, as in S26, and check. |
| Two pictures have swapped halves | A 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 game | A Define used a code below 128. Restart the Einstein. |
| Pressing a level number gives level 1 | The number is more than the levels in the file, or the key was not a digit. |
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.
S37, A Program That Stands On Its Own - compiling Warehouse into a .COM file that runs without Turbo.