
The six levels are part of the program. To change one, you change the program; to add one, you change the program and Count. And in S32 the game will want to remember each level's best score - which no program can do by changing its own constants.
So the levels move to the disc, into a file called LEVELS.DAT, one record per level. The game reads the level it needs when it needs it, and later sections write to the same file: the best scores, and levels you design.
S21's files of records were made for exactly this:
F: file of Level;
Each record is one whole Level - its name, its grid, its start and its best score - and they are numbered from 0. Level N is record N - 1.
ReadLevel reads level N:
Reset(F);
Seek(F, N - 1);
Read(F, L);
Close(F);
It opens the file, goes straight to the record, reads it into L and closes the file again. Closing after every use keeps the disc's directory up to date, as Borland's manual advises (S21) - and the game never has to remember whether the file is open.
The very first time the game runs, there is no LEVELS.DAT. OpenFile finds out, with S21's trick:
{$I-}
Reset(F);
{$I+}
if IOresult <> 0 then
If the file is not there, it makes it: Rewrite creates it, and each of the six plans is turned into a level by MakeLevel and written in. Every run after that finds the file and leaves it alone.
Either way, OpenFile sets Total to the number of levels in the file, with FileSize. From now on the game goes by Total, not by Count - so a file with more levels in it means a game with more levels, and not one line of the game has to change.
That first run writes six levels to the disc, and while the disc is writing the Einstein does not take in keys. Wait for the warehouse to appear before you press anything.
Start WARE5 from WARE4.
Add the file and Total to the variables:
var
L: Level;
F: file of Level;
N, R, C, Total: Integer;
LeftCol, TopRow: Integer;
Wide, High: Integer;
Ch: Char;
Before Start, add the two new procedures:
procedure OpenFile;
var
K: Integer;
begin
Assign(F, 'LEVELS.DAT');
{$I-}
Reset(F);
{$I+}
if IOresult <> 0 then
begin
Rewrite(F);
for K := 1 to Count do
begin
MakeLevel(K);
Write(F, L);
end;
end;
Total := FileSize(F);
Close(F);
end;
procedure ReadLevel;
begin
Reset(F);
Seek(F, N - 1);
Read(F, L);
Close(F);
end;
In Start, MakeLevel(N); becomes:
ReadLevel;
In Won, if N > Count then becomes:
if N > Total then
And in the main program, OpenFile comes first:
begin
OpenFile;
N := 1;
Start;
Starting from
WARE4 from S30, read into a new work file WARE5. Make the changes, CTRL-K CTRL-D, S, R.
What you should see
The same game as before - which is the point. Behind it, the first run made LEVELS.DAT: quit, press D and ENTER, and it is there in the list.
{$I-} and {$I+} round the Reset in OpenFile. Run it on a disc that has no LEVELS.DAT yet (ERA LEVELS.DAT at the 0: prompt, S6, first). What happens, and where does ESC put the cursor?ReadLevel, change Seek(F, N - 1) to Seek(F, N). Which level does Level 1 show?'LEVELS.DAT' to 'LEVELS2.DAT'. Run it, quit, and look at D.31.1 Show how many levels there are on the top line, as Level 1 of 6: First Steps.
31.2 Write a separate short program, LEVLIST, that lists the names of all the levels in LEVELS.DAT. It needs the game's const and type for a level, but none of its procedures.
31.3 Write another, ADDLEVEL, that copies level 1 to the end of the file as a new level called First Again. Then run the game: does it know there is a seventh level?
Worked solutions are in Appendix II.
| Symptom | Cause |
|---|---|
I/O error 01 on the first run | Reset of a file that is not there yet, without {$I-} round it. |
| The first key is ignored, the first time the game runs | The game was writing LEVELS.DAT. Wait for the warehouse. |
A change to Plans makes no difference | The levels now come from LEVELS.DAT, made before the change. Erase it (ERA LEVELS.DAT at 0:) and the game makes a new one from Plans. |
| Every level is the next one | Seek(F, N) for Seek(F, N - 1): records count from 0. |
You have changed the Level record | The records already in LEVELS.DAT were written in the old shape. Erase it, and the game makes a new one. |
The levels live in LEVELS.DAT, a file of Level records. OpenFile makes it from Plans the first time, when {$I-} and IOresult show it is missing, and counts the levels with FileSize. ReadLevel opens the file, Seeks to record N - 1, reads it, and closes it. The game now plays whatever levels the file holds.
S32, Counting Moves - a move counter, and the best score for each level, written back into the file.