Apple I Replica Creation -- Chapter 5: Programming in BASIC
Chapter 5 |
Programming in BASIC |
Introduction
As its name suggests, Beginner's All-Purpose Symbolic Instruction Code (BASIC) is a great high-level programming language for beginners. BASIC was developed at Dartmouth College in 1964 and became the dominant programming language on microcomputers in the 1970s and '80s. If you visit your local library, you'll probably find dozens of books devoted to programming in BASIC, whether for the Apple II, Commodore 64, or IBM PC. All these variations of BASIC have the same base syntax, but they differ in more advanced features. Apple I BASIC is among the simplest of the variations. In this chapter, you'll learn how to set up BASIC on the Apple I and write some simple programs.
Setting Up BASIC
The original Apple I did not have BASIC in ROM. Instead, users had to either load it into RAM using an optional cassette interface, or painstakingly type the entire program in by hand. If you're using a Replica I ROM, you already have BASIC ready to run. Power the system up and press Reset. At the / prompt, type:
E000R
This means "run the code, starting at address $E000." Press Return and a > prompt will appear. You're now running BASIC.
The Apple I supports only uppercase type. However, if you're using a PS/2 keyboard, it will probably be possible for you to input lowercase text. The Replica I video circuitry will properly display lowercase, but the BASIC and Apple I software will not recognize it. Keep Caps Lock on to avoid entering any lowercase letters.
Hello World
First, we'll discuss a few steps to take when you're loading BASIC for Apple I.
The PRINT Command
We'll start at the same place at which every programming introduction starts: "Hello World." Load BASIC and type the following at the prompt:
10 PRINT "HELLO WORLD"
20 END
Type RUN followed by pressing Return, and the program will display:
HELLO WORLD
In the aforementioned example, note the line numbers down the left column of the code. The processor executes statements in numerical order. If, later on, you came back and added the line:
15 PRINT "GOODBYE WORLD"
Line 15 would execute before line 20, even though line 20 was typed in first. If you ran the program, the result would be:
HELLO WORLD
GOODBYE WORLD
To see a list of all your code, type:
LIST
The program you entered will be printed to screen, line by line. If you were to type
10 PRINT "GOODBYE WORLD"
your original line 10 would be overwritten with the new line 10. This is especially useful when you discover a typo.
As you've probably guessed, the PRINT command prints to screen. The END command tells the processor when to stop executing.
Multiple strings can be printed with one PRINT. Separating strings with a semicolon will cause them to be printed without any space between them:
>PRINT "HELLO";"WORLD"
HELLOWORLD
Using commas will insert spaces so that the strings line up in columns:
10 PRINT "1","2"
20 PRINT "428","84"
30 END
>RUN
1 2
428 84
The TAB Command
TAB is used to insert spaces before the next PRINT. This is useful for formatting. For example, TAB 15 indents a line 15 spaces; TAB 20 indents 20 spaces.
10 TAB 15: PRINT "HELLO"
20 TAB 20: PRINT "WORLD"
30 END
>RUN
HELLO
WORLD
A colon ( : ) is used to place two instructions on the same line and can be used with any BASIC instruction, not just with TAB.
The GOTO Command
Suppose we want to write a really obnoxious program that says "Hello World" over and over again. This is where the GOTO command comes into play:
10 PRINT "HELLO WORLD"
20 GOTO 10
30 END
The program loops infinitely, printing "HELLO WORLD" each time, and never reaches line 30.
Welcome, User (Input, Variables, and Strings)
In this section, we'll look at inputting data and storing it in variables. Variables can be one of two types, either integer strings or character strings. An integer may be named with a letter or a letter and a digit (for example, A, N, A1, B8). A character string must be named with a letter and a dollar sign ($; for example, A$, R$, Z$).
Characters are ASCII; therefore, each character in a string occupies 1 byte of memory. BASIC needs to be told how many bytes to allocate to a string, a process called dimensioning. The maximum string length is 255 characters (or bytes). For example:
10 PRINT "WELCOME TO THE APPLE I!"
20 DIM N$(20)
30 INPUT "WHAT IS YOUR NAME", N$
40 INPUT "PICK A NUMBER",A
50 PRINT "YOUR NAME IS "; N$
60 PRINT "YOU PICKED "; A
70 END
The output of this code will look like this:
>RUN
WELCOME TO THE APPLE I!
WHAT IS YOUR NAME?TOM
PICK A NUMBER?5
YOUR NAME IS TOM
YOU PICKED 5
>
You may notice that there is a question mark added after WHAT IS YOUR NAME. A question mark is automatically inserted after each INPUT statement. Unfortunately, there is no way to turn it off.
Let's examine the importance of quotation marks in statements. Note the difference between lines 30 and 40 in this code:
10 DIM N$(2)
20 N$="HI"
30 PRINT N$
40 PRINT "N$"
50 END
>RUN
HI
N$
The first line prints the string contained in the variable N$. The second line, because of the quotes, literally prints "N$."
Calculator (Math)
Apple I BASIC allows simple mathematical functions to be performed directly from the command line. Without writing a program, you can simply type:
>PRINT 8+3
11
>PRINT 3-7
-4
>PRINT (8+3)*4
44
>A=12
>PRINT A-7
5
>B = A*3
>PRINT B
36
>
Apple I BASIC only supports integers; so, if you perform division, you'll get results like this:
>PRINT 38/9
4
You can, however, use MOD (modulus) to calculate the remainder.
>PRINT 38 MOD 9
2
From these two commands, we can ascertain that 38/9 is equal to 4 2/9.
Here's a simple program to add two numbers:
10 INPUT "FIRST NUM",A
20 INPUT "SECOND NUM",B
30 PRINT A+B
40 END
>RUN
FIRST NUM?9872
SECOND NUM?1111
10983
BASIC supports integers in the range of –32,767 to 32,767 (2 bytes). There are several mathematical functions built into BASIC (Table 5.1).
Function | Description |
ABS(N) | Returns the absolute value of N. If N is positive, N will be returned. If N is negative, –N will be returned. |
SGN(N) | Returns 1 if N is positive, 0 if N is 0, and –1 if N is negative. |
RND(N) | Returns a random number between 0 and N - 1 if N is positive. Returns a random number between N + 1 and 0 if N is negative. |
Here's a quick example of the functions in action:
10 A= RND (-10000)
20 PRINT "RANDOM INT IS: ";A
30 PRINT "SIGN OF INT IS: "; SGN (A)
40 PRINT "ABSOLUTE VALUE OF INT IS: "; ABS (A)
50 END
>RUN
RANDOM INT IS: -9758
SIGN OF INT IS: -1
ABSOLUTE VALUE OF INT IS: 9758
Each time you run this program, RND will generate a new random number.
Count Down (FOR/NEXT)
The FOR and NEXT commands create a loop that runs a set number of times:
FOR I=a TO b STEP c
instructions here
NEXT I
In a simple example, a = 1, b = 10, and c = 1. For the first iteration of the loop, a = 0. Then, the NEXT I instruction is reached, and a is incremented by c (in this case, 1). The program continues to loop until b = c. Here's an example:
10 INPUT "ENTER INCREMENT",I
20 INPUT "START WHERE",S
30 FOR V=S TO 0 STEP -I
40 PRINT V
50 NEXT V
60 END
>RUN
ENTER INCREMENT?3
START WHERE?27
27
24
21
18
15
12
9
6
3
0
If STEP is left off the FOR statement, STEP will default to +1.
Some (IF/THEN)
IF/THEN is a very powerful tool that allows the program to branch in two directions. Look at this sample:
10 DIM N$(20)
20 INPUT "WHAT IS YOUR NAME", N$
30 IF N$ = "TOM" THEN 100
40 PRINT "HELLO, STRANGER!"
50 END
100 PRINT "WELCOME BACK, TOM!"
110 END
If the user's name is Tom, the program issues a GOTO that jumps execution to line 100. If it's not Tom, the program continues executing at the next line, which is 40. IF/THEN statements can be used with an instruction. Here's a sample using PRINT:
10 DIM N$(20)
20 INPUT "WHAT IS YOUR NAME", N$
30 IF N$ = "SECRETAGENT" THEN PRINT "THE CROW FLIES AT MIDNIGHT."
40 PRINT "WELCOME TO THE APPLE I, "; N$; "!"
50 END
>RUN
WHAT IS YOUR NAME?TOM
WELCOME TO THE APPLE I, TOM!
>RUN
WHAT IS YOUR NAME?SECRETAGENT
THE CROW FLIES AT MIDNIGHT.
WELCOME TO THE APPLE I, SECRETAGENT!
If you've programmed in other languages, you're used to having an ELSE statement, such as "If a then b else c." Unfortunately, ELSE is not provided by Apple I BASIC.
Expressions
Apple I BASIC supports the following types of expressions:
A = B
A > B
A < B
A >= B (A is greater than or equal to B)
A <= B (A is less than or equal to B)
A <> B (A does not equal B)
A # B (same as A <> B)
Only = and # may be used with strings. These expressions evaluate to 1 if true and 0 if false. For example:
>PRINT 5=5
1
>PRINT 5=6
0
The IF/THEN statement bases its operation on the resulting 1 or 0. In fact, from the command line you can even type:
>IF 1 THEN PRINT "HI"
HI
It's possible to combine multiple statements with the AND and OR commands:
40 IF A=5 AND B=12 THEN PRINT "WINNER!"
50 IF A=7 OR B=19 OR N$="TOM" OR I$="HELLO" THEN PRINT "WHAT AN ODD COMBINATION."
Parentheses can be used for nesting statements, which are useful for ordinary algebra:
>PRINT (5+2)*8
56
More interestingly, parentheticals can also be used with AND/OR statements:
10 A=5
20 B=8
30 C=11
40 IF A=5 AND (B=927 OR C=11) THEN PRINT "CLOSE ENOUGH!"
50 END
>RUN
CLOSE ENOUGH!
Finally, we have NOT. NOT allows us to get the BASIC-equivalent of NAND and NOR logic gates. With it, we can write statements such as:
IF NOT (A=5 AND B=7) THEN PRINT "NOT BOTH, BUT POSSIBLY ONE"
IF NOT (A=9 OR B=2) THEN PRINT "NEITHER"
The GOSUB Command
GOSUB, which is short for "go to subroutine," is like a more advanced GOTO command. Whereas GOTO permanently branches off to a new location, GOSUB lets the user branch off, run a few lines of code, then RETURN where the program left off before branching. It works like this:
10 GOSUB 100
20 GOSUB 100
30 END
100 PRINT "HELLO"
110 RETURN
>RUN
HELLO
HELLO
Here's another example using nested subroutines:
10 PRINT "START"
20 GOSUB 100
30 PRINT "FINISH"
40 END
100 PRINT "SUBROUTINE 1"
110 GOSUB 200
120 RETURN
200 PRINT "SUBROUTINE 2"
220 RETURN
>RUN
START
SUBROUTINE 1
SUBROUTINE 2
FINISH
When GOSUB is called, BASIC records the line number of origin. RETURN is like a GOTO, which goes back to that original point and begins executing at the next line. Up to eight subroutines can be nested. The program above uses two nested subroutines.
GOSUB is a vital tool for structuring programs. It allows us to establish subroutines, which we can repeatedly use within our program. A well-written subroutine may even be worth saving to use in future programs. In the next example, the sample program illustrates the uses of GOSUB and GOTO. It's more complex than the previous programs we've looked at, so I've included REMs (remarks). The REM statements are not executed by BASIC. They are only displayed when the program is LISTed and exist only to provide guidance to those reading the code.
This program is similar to the battle scenes in a traditional text adventure or dungeon game:
10 REM DUNGEON BATTLE
20 DIM I$ (1)
30 REM HEALTH OF MONSTER M AND YOU Y
40 M = RND(1000)
45 PRINT "MONSTER'S HEALTH: ";M
50 Y = RND(1000)
55 PRINT "YOUR HEALTH: ";Y
60 REM WEAPON STRENGTHS OF MONSTER M1 AND YOU Y1
70 M1 = 250
80 Y1 = 250
100 REM USE A GOTO TO MAKE A LOOP.
101 REM IF/THEN'S ARE USED TO BREAK OUT OF THE LOOP.
120 INPUT "DO YOU WANT TO FIGHT OR RUN (F/R)", I$
130 IF I$ = "R" THEN GOTO 200
140 GOSUB 500
150 IF Y < 1 THEN GOTO 400
160 IF M < 1 THEN GOTO 300
170 GOTO 100
200 PRINT "YOU FLEE IN COWARDLY TERROR. "
210 GOTO 1000
300 PRINT "YOU HAVE VANQUISHED THE MONSTER!"
310 GOTO 1000
400 PRINT "THE MONSTER HAS EATEN YOU."
410 GOTO 1000
500 REM ATTACK
510 M = M-RND(Y1)
520 Y = Y-RND(M1)
530 PRINT "MONSTER HEALTH: "; M
540 PRINT "YOUR HEALTH: "; Y
550 RETURN
1000 END
Here are two sample runs of the game:
>RUN
MONSTERS HEALTH: 466
YOUR HEALTH: 758
DO YOU WANT TO FIGHT OR RUN (F/R)?F
MONSTER HEALTH: 335
YOUR HEALTH: 558
DO YOU WANT TO FIGHT OR RUN (F/R)?F
MONSTER HEALTH: 164
YOUR HEALTH: 474
DO YOU WANT TO FIGHT OR RUN (F/R)?F
MONSTER HEALTH: -21
YOUR HEALTH: 408
YOU HAVE VANQUISHED THE MONSTER!
>RUN
MONSTERS HEALTH: 326
YOUR HEALTH: 69
DO YOU WANT TO FIGHT OR RUN (F/R)?F
MONSTER HEALTH: 312
YOUR HEALTH: -20
THE MONSTER HAS EATEN YOU.
Arrays
An array is a collection of variables stored consecutively in memory. They are accessed by a single variable name followed by their array location in parentheses (as a subscript). Table 5.2 shows a sample array named A.
Location | Value |
1 | 89 |
2 | 7 |
3 | 123 |
4 | 2 |
5 | 1015 |
6 | 42 |
7 | 123 |
In this example, 89 would be accessed with A(1), 42 with A(6), and so on. An attempt to access a value outside 1 to 7 will produce an out-of-range error (RANGE ERR).
Like a string, which is actually an array of characters, an array needs to be dimensioned with DIM. Here's a program to create an array similar to the one shown in Table 5.2 and then print all the values:
10 REM DETERMINE ARRAY LENGTH
20 C = RND(20)
30 DIM A(C)
100 REM LOAD VALUES
110 FOR I = 1 TO C
120 A(I) = RND(32767)
130 NEXT I
200 REM PRINT VALUES
210 FOR I=1 TO C
220 PRINT A(I)
230 NEXT I
500 END
>RUN
10411
26608
8259
785
5324
30034
32729
428
Arrays are a useful means of organizing data and are especially well suited to use with FOR/NEXT loops. They also provide the ability to work with a varying number of variables. The execution of the program just shown would not be possible using ordinary variables. When each variable has its own name (for example, A, B), there is no way to loop through them, let alone declare a random number of variables.
Strings, In Depth
Apple I BASIC has considerably advanced string manipulation, given its other limitations. Extracting substrings is simple. A string's length can be retrieved with a single function call. Comparing two strings to see if they're equal is a trivial task.
Substrings
It is possible to select a substring by specifying the start and end points in a subscript. Suppose we have the string:
T$ = "APPLE I REPLICA CREATION"
This string has 24 characters, which are numbered 1 through 24. Substrings are specified in the form of T$(I,J), where I is the location of the first character to be printed and J is the location of the last:
>PRINT T$(1,5)
APPLE
>PRINT T$(7,9)
I R
>PRINT T$(21,21)
T
>PRINT T$(1,24)
APPLE I REPLICA CREATION
It is also possible to specify only the starting point. In which case, all characters from that point on are returned:
>PRINT T$(11)
PLICA CREATION
The LEN Function
LEN returns the number of characters in a string. For example:
>DIM R$(20)
>R$ = "REPLICA"
>PRINT LEN(R$)
7
This is useful when you're using a FOR/NEXT statement to cycle through each character in a string. LEN can be used to tell the FOR/NEXT when to stop. LEN also makes it easy to combine strings, as shown in the next section.
Appending Strings
It's easy to overwrite a string, using a command such as:
DIM $S(20)
$S = "ORIGINAL STRING"
$S = "NEW STRING"
It is also possible to append one string to the end of another. To do this, specify the location where the appended string should start. For example:
>DIM A$(30)
>DIM B$(30)
>A$ = "ABCDEFG"
>B$ = "HIJKLMNOP"
>A$(LEN(A$)+1) = B$
>PRINT A$
ABCDEFGHIJKLMNOP
If the location specified is before the end of the string, the rest of the string will be overwritten. Continuing from the previous example:
>DIM C$(30)
>C$ = "123"
>A$(4) = C$
>PRINT A$
ABC123
Conditionals
The = symbol can also be used to compare two strings. This works for simple comparisons of entire strings:
>DIM A$(30)
>DIM B$(30)
>DIM C$(30)
>A$ = "HELLO"
>B$ = "HELLO"
>C$ = "WORLD"
>PRINT (A$ = B$)
1
>PRINT (A$ = C$)
0
A 1 means that the strings are equal. A 0 means they are different. These comparisons can also be used in IF/THEN statements.
It is also possible to compare any two substrings:
>DIM A$(30)
>DIM B$(30)
>A$ = "NONETHELESS"
>B$ = "JOHANN THEILE"
>PRINT (A$(5,7) = B$(8,10))
1
Sample String Program
This simple program combines substrings, the LEN function, and string comparisons to reverse the order of a name. Here is a sample run of the program:
>RUN
ENTER YOUR FULL NAME?JAMES CONNOLLY
YOUR NAME IS: CONNOLLY, JAMES
The program in full is as follows:
10 REM FULL NAME, FIRST NAME, LAST NAME
15 DIM N$(50)
20 DIM F$(50)
25 DIM L$(50)
30 REM REVERSED NAME
35 DIM R$(50)
50 REM LOAD FULL NAME
55 INPUT "ENTER YOUR FULL NAME", N$
100 REM FIND FIRST NAME BY SEARCH FOR SPACE
105 FOR I = 1 TO LEN(N$)
110 IF N$(I,I) = " " THEN F$ = N$(1,I-1)
115 NEXT I
150 REM LAST NAME STARTS ONE CHAR AFTER THE
155 REM END OF THE FIRST NAME AND ENDS AT
160 REM END OF THE FULL NAME
165 L$ = N$(LEN(F$)+2, LEN(N$))
200 REM REARRANGE NAMES
205 R$ = L$
210 R$(LEN(R$)+1) = ", "
215 R$(LEN(R$)+1) = F$
250 PRINT "YOUR NAME IS: "; R$
300 REM WERE THOSE REALLY DIFFERENT NAMES?
305 IF F$ = L$ THEN PRINT "ARE YOU TELLING THE TRUTH?"
350 END
You might have noticed that the loop at lines 100–115 searches the entire string, even though there's no reason for it to continue after finding the space. Here's an alternative that breaks out of the loop once the space is found:
100 REM FIND FIRST NAME BY SEARCH FOR SPACE
105 FOR I = 1 TO LEN(N$)
110 IF N$(I,I) = " " THEN F$ = N$(1,I-1)
112 IF N$(I,I) = " " THEN 150
115 NEXT I
PEEK and POKE
PEEK and POKE are used for manually accessing memory locations. This is useful if you're interfacing with an input/output device or writing part of your program in assembly. Inconveniently, BASIC uses decimal for PEEKs and POKEs; as a result, you'll have to covert your address from hexadecimal to decimal (as discussed in Chapter 3) before POKEing or PEEKing.
To place the value 42 in location 9000, type:
POKE 9000,42
To read it back and print it to the screen, type:
PRINT PEEK (9000)
The Apple I has 65,535 memory locations. Apple I BASIC allows for integers in the range of –32,767 to 32,767. Memory locations 0 through 32767 are accessed directly. Addresses above 32,767 are accessed using Two's Complement notation (Table 5.3).
To get the Two's Complement notation for –2:
1. Convert +2 to binary.
0000 0000 0000 0010
2. Take the complement.
1111 1111 1111 1101
3. Add 1.
1111 1111 1111 1110
4. Convert to hexadecimal, for ease of use.
$FFFE
Two's Complement Notation | Hexadecimal Value |
+32,767 | $7FFF |
+32,766 | $7FFE |
... | ... |
+1 | $0001 |
0 | $0000 |
-1 | $FFFF |
-2 | $FFFE |
... | ... |
-32,767 | $8001 |
-32,768 | $8000 |
Since location $8000 is represented by a value less than –32,767, it cannot be reached with BASIC.
The CALL Command
CALL is used to access a subroutine written in Assembly. It is used in the manner:
CALL n
Here, n is the memory location of the subroutine, which is represented in decimal format. In your Assembly subroutine, use an RTS to return control to the BASIC program.
CALL is useful if you want to write most of your program in BASIC but occasionally need a fast Assembly-language subroutine. Table 5.4 lists CALL commands and their meanings.
Command | Explanation |
AUTO a, b | AUTO automatically numbers lines for you as they are typed. a is the first line number. b is the increment between lines. If b is not specified, it defaults to 10. Ctrl-D terminates AUTO mode. |
CLR | CLR resets all variables, FOR loops, GOSUBs, arrays, and strings. It does not delete the program in memory. |
DEL a, b | DEL deletes all lines of code between a and b, inclusive. If b is omitted, only line a is deleted. |
LIST a, b | LIST displays all lines of code between a and b, inclusive. If b is omitted, only line a is displayed. If both are omitted, all lines are displayed. |
RUN a | RUN does a CLR and then begins executing code starting at line a. If a is omitted, the program begins executing at the first line. |
SCR | SCR scratches (deletes) the entire program and clears memory. |
LOMEM = n | LOMEM sets the memory floor for user programs. It is initialized to 2048. LOMEM clears all user programs and values. |
HIMEM = n | HIMEM sets the memory ceiling for user programs. It is initialized to 4096. Replica I users can increase this value to 32767 to take advantage of the Replica I's extended memory. HIMEM clears all user programs and values. |
Table 5.5 lists CALL error codes and their meanings.
Error Code | Explanation |
>256 ERR | A value restricted to one byte was outside the allowed range of 0 to 255. |
>32767 ERR | The value entered or calculated was outside the range of (–32767, 32767) |
>8 FORS ERR | There are more than eight nested FOR loops. |
>8 GOSUBS ERR | There are more than eight nested subroutines. |
BAD BRANCH ERR | There is an attempt to branch to a line number that does not exist. |
BAD NEXT ERR | A NEXT statement is encountered without a corresponding FOR. |
BAD RETURN ERR | A RETURN statement is encountered without a corresponding GOSUB. |
DIM ERR | There is an attempt to dimension a character string that has already been dimensioned. |
END ERR | There is no END command at the end of the program. |
MEM FULL ERR | Occurs when the size of an array exceeds the amount of space available in memory. |
RANGE ERR | The requested value is smaller than 1 or larger than the maximum value of the array or string. |
RETYPE LINE | Data entered for an INPUT is not of the correct type. |
STR OVFL ERR | The maximum length of the string is exceeded. |
STRING ERR | The attempted string operation was illegal. |
SYNTAX ERR | The line is not properly formatted or it contains some typo. |
TOO LONG ERR | There are too many nested parenthesis in a statement. |
Richard III: Interactive Fiction
Richard III is a piece of interactive fiction based on Shakespeare's play of the same name. It is presented here to give you an example of how a small program might be constructed. The story was written by Sarah McMenomy.
Walkthrough
Before writing any code, it's necessary to figure out the basics of how the game is going to work. McMenomy wrote a walkthrough of Richard III. Let's look at her original design:
Intro:
King Richard: Is thy name Tyrrel?
Tyrrel: James Tyrrel, and your most obedient subject.
King Richard: Art thou indeed?
Tyrrel: Prove me, my gracious lord.
King Richard: Dar'st' thou resolve to kill a friend of mine?
Tyrrel: Please you;
But I had rather kill two enemies.
King Richard: Why, then thou hast it! Two deep enemies,
Foes to my rest and my sweet sleep's disturbers,
Are they that I would have thee deal upon:
Tyrrel, I mean those bastards in the Tower.
Tyrrel: Let me have open means to come to them,
And soon I'll rid you from the fear of them.
King Richard: Thou sing'st sweet music. Hark, come hither, Tyrrel.
Go, by this token. Rise, and lend thine ear.
There is no more but so: say it is done,
And I will love thee and prefer thee for it.
Tyrrel: I will dispatch it straight.
Outside Tower.
Ravens are flying around your head as you stand outside the tower.
There are two spigots on the wall; one says "Haute," and the other,
"Caulde." "Caulde" is on.
>N
The Ravens swoop down and peck at you, blocking your entrance.
>Turn Haute on
"Haute" is now on.
>Turn Caulde off
"Caulde" is now off. The ravens are happily bathing in the hot water.
>N
You enter the tower.
Bottom of tower.
You are at the bottom of the tower. There is a dagger on the floor, and
a slip of paper underneath it. There is a guard on the stairs.
>Take dagger and paper
Taken.
>Read paper
The paper says "1483."
>Up
The guard blocks your ascent.
>Kill/stab guard
The guard crumples to the floor, falling on the dagger.
>Up
You ascend the stairs.
Middle of Tower.
You are in the middle of the tower. There is a key in the corner. There
are four number dials on the door to the north.
>Take key
Taken.
>N
The door is closed.
>Open door
You can't.
>Read dials
The dials read "0000."
>Turn first dial to 1
The dial clicks.
>Turn second dial to 4
The dial makes a whir.
>Turn third dial to 8
The dial squeaks.
>Turn fourth dial to 3
The dial whines.
>Open door
The door opens.
>N
You are so close...
Top of tower.
You are at the top of the tower. There is a door to the north.
>Unlock door
You push the key into the door and it swings open; you can see shapes
silhouetted in the moonlight.
>N
You enter the chamber of the sleeping princes...
Tyrrel: The tyrannous and bloody act is done,
The most arch deed of piteous massacre
That ever yet this land was guilty of.
Dighton and Forrest, who I did suborn
To do this piece of ruthless butchery,
Albeit they were fleshed villains, bloody dogs,
Melted with tenderness and mild compassion,
Wept like to children in their deaths' sad story.
'O, thus,' quoth Dighton, 'lay the gentle babes.'
'Thus, thus,' quoth Forrest, 'girdling one another
Within their alabaster innocent arms.
Their lips were four red roses on a stalk,
And in their summer beauty kissed each other.
A book of prayers on their pillow lay,
Which once,' quoth Forrest, 'almost changed my mind;
But, O! The devil' - there the villain stopped;
When Dighton thus told on - 'We smothered
The most replenished sweet work of nature
That from the prime creation e'er she framed.'
Hence both are gone with conscience and remorse:
They could not speak; and so I left them both,
To bear this tidings to the bloody king.
Your villainous task is done; long live King Richard!
***You have won***
I originally wanted to implement a command parser, but the complexity of writing this in BASIC would have made for a very poor beginner's example. To simplify things, I decided to make the options multiple-choice. The game is less interesting this way, but it also makes for an easier demonstration.
Structure
Now that we know what the game should look like from the user's perspective, let's examine the structures needed to implement it.
Each room will be a subroutine; consequently, we can allocate each a range of lines (Table 5.6).
Room | Line Allocation |
Outside Tower | 1,000–1,999 |
Bottom of Tower | 2,000–2,999 |
Middle of Tower | 3,000–3,999 |
Top of Tower | 4,000–4,999 |
Most of the game will take place within the code allocated for the rooms shown in Table 5.6. However, we can make things simpler by using a few other subroutines. The Intro and Conclusion speeches can each be their own subroutines. Likewise, we can use a single subroutine to print the room descriptions. The description will be stored in a string by the room and then used by the subroutine. This will allow us to change the layout for all descriptions by simply modifying one subroutine (Table 5.7).
Subroutine | Line Allocation |
Introduction | 30,000–30,499 |
Conclusion | 30,500–30,999 |
Initialize | 31,000–31,999 |
PRINT Room | 32,000–32,499 |
Variables
Next, let's look at the variables we'll need. Ideally, each string of text would be stored in its own variable, making it easy to update and access data. Unfortunately, Apple I BASIC only allows 26 string variables, so the less commonly used strings will have to be stored directly in PRINT statements (Tables 5.8–5.12).
Object | Variable Name | Description |
Room title | R$ | These variables will be overwritten at the beginning of each room and then used by the Print Room subroutine to display the room's information. |
Room description | D$ | |
Temporary | T$ | A temporary variable, which can be used for any purpose. |
Choice | Y | The user's input at the multiple choice. |
Increment variable | I | This variable is used by the FOR/NEXT loops. |
Object | Variable Name | Description |
Haute spigot | H1 | The haute and caulde spigots are either on (1) or off (0). By default, haute is off and caulde is on. |
Caulde spigot | C1 |
Object | Variable Name | Description |
Dagger | D2 | The dagger is either in the player's possession (1) or not (0). |
Paper | P2 | The paper is either in the player's possession (1) or not (0). |
Guard | G2 | The guard is either alive (1) or dead (0). |
Object | Variable Name | Description |
Key | K3 | The key is either in the player's possession (1) or not (0). |
Door | D3 | The door is either in the open (1) or closed (0) position. |
Lock | L3 | An array of four integers holds the lock combinations. Each value is initialized to 0. |
Object | Variable Name | Description |
Door | D4 | The door is either unlocked (1) or locked (0). |
Skeleton
Each phase of the game is its own subroutine. Rooms can easily be rearranged. Adding another room simply requires adding another subroutine. Italicized names are used in place of line numbers. Omitting line numbers in the program's rough draft will make it easier to make changes along the way.
GOSUB initialize
GOSUB introduction
GOSUB outside_tower
GOSUB bottom_tower
GOSUB middle_tower
GOSUB top_tower
GOSUB conclusion
END
Initialization
The program should start by initializing all the variables we're going to use.
initialize:
DIM R$(255)
R$ = "X" : REM ROOM TITLE
DIM D$(255)
D$ = "X" : REM ROOM DESCRIPTION
DIM T$(255)
T$ = "X" : REM TEMPORARY VARIABLE
DIM L3(4) : REM LOCK COMBINATION
FOR I = 1 TO 4
L3(I) = 0 : REM LOCK COMBINATION SET TO 0000
NEXT I
H1 = 0 : REM HAUTE IS OFF
C1 = 1 : REM CAULDE IS ON
D2 = 0 : REM NO DAGGER
P2 = 0 : REM NO PAPER
G2 = 1 : REM GUARD ALIVE
K3 = 0 : REM NO KEY
D3 = 0 : REM DOOR CLOSED
D4 = 0 : REM DOOR LOCKED
RETURN
Introduction and Conclusion Subroutines
We can address the subroutines for the introduction and conclusion next because they are extremely basic. These two methods consist of nothing more than a series of PRINT statements followed by a RETURN to give control back to the calling routine.
An INPUT line halfway through pauses the scrolling text so that the user has time to read it. The user need not enter any data, but only presses keys for the program to continue.
When a line of poetry exceeds 40 characters, it is manually divided into two lines. The second line is indented four spaces using TABs.
PRINT "KING RICHARD: IS THY NAME TYRREL?"
PRINT "TYRREL: JAMES TYRREL, AND YOUR MOST"
TAB 4: PRINT "OBEDIENT SUBJECT."
PRINT "KING RICHARD: ART THOU INDEED?"
PRINT "TYRREL: PROVE ME, MY GRACIOUS LORD."
PRINT "KING RICHARD: DAR'ST' THOU RESOLVE TO"
TAB 4: PRINT "KILL A FRIEND OF MINE?"
PRINT "TYRREL: PLEASE YOU;"
TAB 4: PRINT "BUT I HAD RATHER KILL TWO ENEMIES."
PRINT "KING RICHARD: WHY, THEN THOU HAST IT!"
TAB 4: PRINT "TWO DEEP ENEMIES,"
PRINT "FOES TO MY REST AND MY SWEET SLEEP'S"
TAB 4: PRINT "DISTURBERS,"
PRINT "ARE THEY THAT I WOULD HAVE THEE DEAL"
TAB 4: PRINT "UPON:"
PRINT "TYRREL, I MEAN THOSE BASTARDS IN THE"
TAB 4: PRINT "TOWER."
PRINT "TYRREL: LET ME HAVE OPEN MEANS TO COME"
TAB 4: PRINT "TO THEM,"
PRINT "AND SOON I'LL RID YOU FROM THE FEAR OF"
TAB 4: PRINT "THEM."
PRINT "KING RICHARD: THOU SING'ST SWEET MUSIC."
TAB 4: PRINT "HARK, COME HITHER, TYRREL."
INPUT "CONTINUE",T$
PRINT "GO, BY THIS TOKEN. RISE, AND LEND THINE"
TAB 4: PRINT "EAR."
PRINT "THERE IS NO MORE BUT SO: SAY IT IS DONE,"
PRINT "AND I WILL LOVE THEE AND PREFER THEE FOR"
TAB 4: PRINT "IT."
PRINT "TYRREL: I WILL DISPATCH IT STRAIGHT."
RETURN
The conclusion is nearly identical:
PRINT "TYRREL: THE TYRANNOUS AND BLOODY ACT IS"
TAB 4: PRINT "DONE,"
PRINT "THE MOST ARCH DEED OF PITEOUS MASSACRE"
PRINT "THAT EVER YET THIS LAND WAS GUILTY OF."
PRINT "DIGHTON AND FORREST, WHO I DID SUBORN"
PRINT "TO DO THIS PIECE OF RUTHLESS BUTCHERY,"
PRINT "ALBEIT THEY WERE FLESHED VILLAINS,"
TAB 4: PRINT "BLOODY DOGS,"
PRINT "MELTED WITH TENDERNESS AND MILD"
TAB 4: PRINT "COMPASSION,"
PRINT "WEPT LIKE TO CHILDREN IN THEIR DEATHS'"
TAB 4: PRINT "SAD STORY."
PRINT "'O, THUS,' QUOTH DIGHTON, 'LAY THE"
TAB 4: PRINT "GENTLE BABES.'"
PRINT "'THUS, THUS,' QUOTH FORREST,"
TAB 4: PRINT "'GIRDLING ONE ANOTHER"
PRINT "WITHIN THEIR ALABASTER INNOCENT ARMS."
PRINT "THEIR LIPS WERE FOUR RED ROSES ON A"
TAB 4: PRINT "STALK,"
INPUT "CONTINUE", T$
PRINT "AND IN THEIR SUMMER BEAUTY KISSED EACH"
TAB 4: PRINT "OTHER."
PRINT "A BOOK OF PRAYERS ON THEIR PILLOW LAY,"
PRINT "WHICH ONCE,' QUOTH FORREST, 'ALMOST"
TAB 4: PRINT "CHANGED MY MIND;"
PRINT "BUT, O! THE DEVIL' - THERE THE"
TAB 4: PRINT "VILLAIN STOPPED;"
PRINT "WHEN DIGHTON THUS TOLD ON - 'WE"
TAB 4: PRINT "SMOTHERED"
PRINT "THE MOST REPLENISHED SWEET WORK OF NATURE"
PRINT "THAT FROM THE PRIME CREATION E'ER SHE"
TAB 4: PRINT "FRAMED.'"
PRINT "HENCE BOTH ARE GONE WITH CONSCIENCE AND"
TAB 4: PRINT "REMORSE:"
PRINT "THEY COULD NOT SPEAK; AND SO I LEFT THEM"
TAB 4: PRINT "BOTH,"
PRINT "TO BEAR THIS TIDINGS TO THE BLOODY KING."
INPUT "CONTINUE", T$
PRINT "YOUR VILLAINOUS TASK IS DONE."
PRINT "LONG LIVE KING RICHARD!"
PRINT "***YOU HAVE WON***"
RETURN
PRINT Room Subroutine
PRINT Room is so simple it barely deserves its own subroutine. I wrote it this way to allow for customization. Only one line of code has to be changed to modify the display of every room title or description.
TAB 10: PRINT T$
PRINT D$
INPUT "CONTINUE",T$
RETURN
Outside Tower
Let's examine the first room. The title and description variables are set and the PRINT Room subroutine is called. Next, the program enters the CHOICE loop. The options are printed and IF statements are used to choose where to go next. Some options will print a message and return the user to the loop. Others will enter a subroutine. The Haute and Caulde subroutines allow the user to use the H1 and C1 variables. When H1 and C1 are set correctly, the CHOICE loop jumps to NEXT_LEVEL and then returns from the subroutine.
The Haute and Caulde subroutines take their variables, H1 and C1 respectively, and invert their values from 0 to 1 or 1 to 0. (Though they are technically integers, we're using them as Boolean—true or false—variables.) In some languages there is an instruction for this, but in Apple I BASIC there is not. Instead, the Haute and Caulde subroutines demonstrate two different methods for inverting a Boolean variable.
T$ = "OUTSIDE THE TOWER"
D$ = " RAVENS ARE FLYING AROUND YOUR HEAD AS YOU STAND OUTSIDE THE TOWER.
THERE ARE TWO SPIGOTS ON THE WALL; ONE SAYS 'HAUTE,' AND THE OTHER,
'CAULDE.' 'CAULDE' IS ON."
GOSUB print_room
choose:
PRINT "1) ENTER THE TOWER"
PRINT "2) TURN HAUTE SPIGOT"
PRINT "3) TURN CAULDE SPIGOT"
INPUT "CHOICE", Y
IF Y = 1 AND H1 = 1 AND C1 = 0 THEN next_level
IF Y = 1 THEN PRINT "THE RAVENS SWOOP DOWN AND PECK AT YOU, BLOCKING YOUR ENTRANCE."
IF Y = 2 THEN GOSUB haute
IF Y = 3 THEN GOSUB caulde
INPUT "CONTINUE",T$
GOTO choose
next_level:
PRINT "YOU ENTER THE TOWER."
RETURN
haute:
H1 = H1 + 1
IF H1 = 2 THEN H1 = 0
IF H1 = O THEN PRINT "HAUTE IS NOW OFF."
IF H1 = 1 THEN PRINT "HAUTE IS NOW ON."
RETURN
caulde:
C1 = 1 – C1
IF C1 = O THEN PRINT "CAULDE IS NOW OFF."
IF C1 = 1 THEN PRINT "CAULDE IS NOW ON."
RETURN
Bottom of the Tower
The most interesting feature in this room is the behavior of the paper. The option READ PAPER is only displayed, and only works, if the paper is in the player's possession.
T$ = "BOTTOM OF THE TOWER"
D$ = "YOU ARE AT THE BOTTOM OF THE TOWER. THERE IS A DAGGER ON THE FLOOR, AND A SLIP OF PAPER UNDERNEATH IT. THERE IS A GUARD ON THE STAIRS."
print_room
choose:
PRINT 1) "ATTACK GUARD"
PRINT 2) "GO UP STAIRS"
PRINT 3) "PICK UP PAPER"
PRINT 4) "PICK UP DAGGER"
IF P2 = 1 THEN PRINT "5) READ PAPER"
INPUT "CHOICE", Y
IF Y = 1 THEN GOSUB attack_guard
IF Y = 2 AND G2 = 0 THEN GOTO next_level
IF Y = 2 THEN PRINT "THE GUARD BLOCKS YOUR ASCENT."
IF Y = 3 THEN GOSUB get_paper
IF Y = 4 THEN GOSUB get_dagger
IF Y = 5 AND P2 = 1 THEN PRINT "THE PAPER SAYS '1482'."
INPUT "CONTINUE",T$
GOTO choose
next_level:
PRINT "YOU ASCEND THE STAIRS."
RETURN
get_paper:
IF P2 = 1 THEN PRINT "YOU ALREADY HAVE THE PAPER."
IF P2 = 1 THEN RETURN
P2 = 1
PRINT "YOU TAKE THE PAPER."
RETURN
get_dagger:
IF D2 = 1 THEN PRINT "YOU ALREADY HAVE THE DAGGER."
IF D2 = 1 THEN RETURN
D2 = 1
PRINT "YOU TAKE THE DAGGER."
RETURN
attack_guard:
IF D2 = 1 THEN PRINT "THE GUARD KNOCKS YOU TO THE GROUND."
IF D2 = 1 THEN RETURN
G2 = 0
PRINT "THE GUARD CRUMPLES TO THE FLOOR, FALLING ON THE DAGGER."
RETURN
Middle of the Tower
The "combination lock" in this room is a four-integer array. Only when all four values are correctly set via the ENTER_COMBINATION subroutine can the player continue to the next room.
T$ = "MIDDLE OF THE TOWER"
D$ = "YOU ARE IN THE MIDDLE OF THE TOWER. THERE IS A KEY IN THE CORNER. THERE ARE FOUR NUMBER DIALS ON THE DOOR TO THE NORTH."
print_room
choose:
PRINT "1) PICK UP KEY"
PRINT "2) OPEN DOOR"
PRINT "3) ENTER COMBINATION"
PRINT "4) ENTER ROOM"
INPUT "CHOICE", Y
IF Y = 1 THEN GOSUB get_key
IF Y = 2 AND L3(1) = 1 AND L3(2) = 4 AND L3(3) = 8 AND L3(4) = 3 THEN GOSUB open_door
IF Y = 2 THEN PRINT "THE COMBINATION IS NOT CORRECT."
IF Y = 3 THEN GOSUB enter_combination
IF Y = 4 AND D3 = 1 THEN next_level
IF Y = 4 THEN PRINT "THE DOOR IS CLOSED."
INPUT "CONTINUE",T$
GOTO choose
next_level:
PRINT "YOU ARE SO CLOSE..."
RETURN
get_key:
IF K3 = 1 THEN PRINT "YOU ALREADY HAVE THE KEY."
IF K3 = 1 THEN RETURN
K3 = 1
PRINT "YOU TAKE THE KEY."
RETURN
enter_combination:
INPUT "TURN FIRST DIAL TO", L3(1)
PRINT "THE DIAL CLICKS."
INPUT "TURN SECOND DIAL TO", L3(2)
PRINT "THE DIAL WHIRRS."
INPUT "TURN THE THIRD DIAL TO", L3(3)
PRINT "THE DIAL SQUEAKS."
INPUT "TURN THE FOURTH DIAL TO", L3(4)
PRINT "THE DIAL WHINES. "
RETURN
open_door:
IF D3 = 0 THEN PRINT "THE DOOR IS LOCKED."
IF D3 = 0 THEN RETURN
PRINT "THE DOOR OPENS."
D3 = 1
RETURN
Top of the Tower
The final room is trivial. The door is unlocked with the key from the previous room—but only if the player picked it up! If you're considering to expand this game, the option to move freely between rooms, picking up and dropping objects, would surely be a welcome feature.
T$ = "TOP OF THE TOWER"
D$ = "YOU ARE AT THE TOP OF THE TOWER. THERE IS A DOOR TO THE NORTH."
print_room
choose:
PRINT "1) UNLOCK THE DOOR"
PRINT "2) ENTER THE CHAMBER."
INPUT "CHOICE", Y
IF Y = 1 THEN GOSUB unlock_door
IF Y = 2 AND D4 = 1 THEN next_level
IF Y = 2 THEN PRINT "THE DOOR IS LOCKED."
INPUT "CONTINUE",T$
GOTO choose
next_level:
PRINT "YOU ENTER THE CHAMBER OF THE SLEEPING PRINCESS... "
RETURN
unlock_door:
IF D4 = 1 THEN PRINT "THE DOOR IS ALREADY UNLOCKED"
IF D4 = 1 THEN RETURN
D4 = 1
PRINT "YOU PUSH THE KEY INTO THE DOOR AND IT SWINGS OPEN; YOU CAN SEE SHAPES SILHOUETTED IN THE MOONLIGHT."
RETURN
Richard III Code
Here is the complete code for Richard III. It can also be found in the Supplemental Software package, so those with a serial I/O board from Briel Computers will be able to transfer it to their replica via the terminal.
The italicized headers from earlier sections have been replaced with REM lines to allow them to be stored in the program. Before you begin entering lines, be sure to increase HIMEM to 32767. This program is too large to run in the standard 8K.
10 REM RICHARD III: (BARELY) INTERACTIVE FICTION
30 GOSUB 31000 : REM INITIALIZE
40 GOSUB 30000 : REM INTRODUCTION
50 GOSUB 1000 : REM OUTSIDE OF TOWER
60 GOSUB 2000 : REM BOTTOM OF TOWER
70 GOSUB 3000 : REM MIDDLE OF TOWER
80 GOSUB 4000 : REM TOP OF TOWER
90 GOSUB 30500 : REM CONCLUSION
100 END
31000 REM INITIALIZE
31010 DIM R$(255)
31015 R$ = "X" : REM ROOM TITLE
31020 DIM D$(255)
31025 D$ = "X" : REM ROOM DESCRIPTION
31030 DIM T$(255)
31035 T$ = "X" : REM TEMPORARY VARIABLE
31040 DIM L3(4) : REM LOCK COMBINATION
31045 FOR I = 1 TO 4
31050 L3(I) = 0 : REM LOCK COMBINATION SET TO 0000
31055 NEXT I
31060 H1 = 0 : REM HAUTE IS OFF
31065 C1 = 1 : REM CAULDE IS ON
31070 D2 = 0 : REM NO DAGGER
31075 P2 = 0 : REM NO PAPER
31080 G2 = 1 : REM GUARD ALIVE
31085 K3 = 0 : REM NO KEY
31090 D3 = 0 : REM DOOR CLOSED
31095 D4 = 0 : REM DOOR LOCKED
31100 RETURN
30000 REM INTRODUCTION
30010 PRINT "KING RICHARD: IS THY NAME TYRREL?"
30015 PRINT "TYRREL: JAMES TYRREL, AND YOUR MOST"
30020 TAB 4: PRINT "OBEDIENT SUBJECT."
30025 PRINT "KING RICHARD: ART THOU INDEED?"
30030 PRINT "TYRREL: PROVE ME, MY GRACIOUS LORD."
30035 PRINT "KING RICHARD: DAR'ST' THOU RESOLVE TO"
30040 TAB 4: PRINT "KILL A FRIEND OF MINE?"
30045 PRINT "TYRREL: PLEASE YOU;"
30050 TAB 4: PRINT "BUT I HAD RATHER KILL TWO ENEMIES."
30055 PRINT "KING RICHARD: WHY, THEN THOU HAST IT!"
30060 TAB 4: PRINT "TWO DEEP ENEMIES,"
30065 PRINT "FOES TO MY REST AND MY SWEET SLEEP'S"
30070 TAB 4: PRINT "DISTURBERS,"
30075 PRINT "ARE THEY THAT I WOULD HAVE THEE DEAL"
30080 TAB 4: PRINT "UPON:"
30085 PRINT "TYRREL, I MEAN THOSE BASTARDS IN THE"
30090 TAB 4: PRINT "TOWER."
30095 PRINT "TYRREL: LET ME HAVE OPEN MEANS TO COME"
30100 TAB 4: PRINT "TO THEM,"
30105 PRINT "AND SOON I'LL RID YOU FROM THE FEAR OF"
30110 TAB 4: PRINT "THEM."
30115 PRINT "KING RICHARD: THOU SING'ST SWEET MUSIC."
30120 TAB 4: PRINT "HARK, COME HITHER, TYRREL."
30125 INPUT "CONTINUE",T$
30130 PRINT "GO, BY THIS TOKEN. RISE, AND LEND THINE"
30135 TAB 4: PRINT "EAR."
30140 PRINT "THERE IS NO MORE BUT SO: SAY IT IS DONE,"
30145 PRINT "AND I WILL LOVE THEE AND PREFER THEE FOR"
30150 TAB 4: PRINT "IT."
30155 PRINT "TYRREL: I WILL DISPATCH IT STRAIGHT."
30160 INPUT "CONTINUE",T$
30165 RETURN
30500 REM CONCLUSION
30505 PRINT "TYRREL: THE TYRANNOUS AND BLOODY ACT IS"
30510 TAB 4: PRINT "DONE,"
30515 PRINT "THE MOST ARCH DEED OF PITEOUS MASSACRE"
30520 PRINT "THAT EVER YET THIS LAND WAS GUILTY OF."
30525 PRINT "DIGHTON AND FORREST, WHO I DID SUBORN"
30530 PRINT "TO DO THIS PIECE OF RUTHLESS BUTCHERY,"
30535 PRINT "ALBEIT THEY WERE FLESHED VILLAINS,"
30540 TAB 4: PRINT "BLOODY DOGS,"
30545 PRINT "MELTED WITH TENDERNESS AND MILD"
30550 TAB 4: PRINT "COMPASSION,"
30555 PRINT "WEPT LIKE TO CHILDREN IN THEIR DEATHS'"
30560 TAB 4: PRINT "SAD STORY."
30565 PRINT "'O, THUS,' QUOTH DIGHTON, 'LAY THE"
30570 TAB 4: PRINT "GENTLE BABES.'"
30575 PRINT "'THUS, THUS,' QUOTH FORREST,"
30580 TAB 4: PRINT "'GIRDLING ONE ANOTHER"
30585 PRINT "WITHIN THEIR ALABASTER INNOCENT ARMS."
30590 PRINT "THEIR LIPS WERE FOUR RED ROSES ON A"
30595 TAB 4: PRINT "STALK,"
30600 INPUT "CONTINUE", T$
30605 PRINT "AND IN THEIR SUMMER BEAUTY KISSED EACH"
30610 TAB 4: PRINT "OTHER."
30615 PRINT "A BOOK OF PRAYERS ON THEIR PILLOW LAY,"
30620 PRINT "WHICH ONCE,' QUOTH FORREST, 'ALMOST"
30625 TAB 4: PRINT "CHANGED MY MIND;"
30630 PRINT "BUT, O! THE DEVIL' - THERE THE"
30635 TAB 4: PRINT "VILLAIN STOPPED;"
30640 PRINT "WHEN DIGHTON THUS TOLD ON - 'WE"
30645 TAB 4: PRINT "SMOTHERED"
30650 PRINT "THE MOST REPLENISHED SWEET WORK OF NATURE"
30655 PRINT "THAT FROM THE PRIME CREATION E'ER SHE"
30660 TAB 4: PRINT "FRAMED.'"
30665 PRINT "HENCE BOTH ARE GONE WITH CONSCIENCE AND"
30670 TAB 4: PRINT "REMORSE:"
30675 PRINT "THEY COULD NOT SPEAK; AND SO I LEFT THEM"
30680 TAB 4: PRINT "BOTH,"
30685 PRINT "TO BEAR THIS TIDINGS TO THE BLOODY KING."
30690 INPUT "CONTINUE", T$
30700 PRINT "YOUR VILLAINOUS TASK IS DONE."
30705 PRINT "LONG LIVE KING RICHARD!"
30710 PRINT
30715 PRINT "***YOU HAVE WON***"
30720 INPUT "CONTINUE",T$
30725 RETURN
32000 REM PRINT ROOM
32010 TAB 10: PRINT T$
32015 PRINT D$
32020 INPUT "CONTINUE",T$
32025 RETURN
1000 REM OUTSIDE THE TOWER
1010 T$ = "OUTSIDE THE TOWER"
1015 D$ = "RAVENS ARE FLYING AROUND YOUR HEAD AS YOU STAND OUTSIDE THE TOWER. THERE ARE TWO SPIGOTS ON THE WALL;"
1016 D$(LEN(D$)+1) = "ONE SAYS 'HAUTE,' AND THE OTHER, 'CAULDE.' 'CAULDE' IS ON."
1020 GOSUB 32000
1025 PRINT "1) ENTER THE TOWER"
1030 PRINT "2) TURN HAUTE SPIGOT"
1035 PRINT "3) TURN CAULDE SPIGOT"
1040 INPUT "CHOICE", Y
1045 IF Y = 1 AND H1 = 1 AND C1 = 0 THEN 1200
1050 IF Y = 1 THEN PRINT "THE RAVENS SWOOP DOWN AND PECK AT YOU, BLOCKING YOUR ENTRANCE."
1060 IF Y = 2 THEN GOSUB 1300
1065 IF Y = 3 THEN GOSUB 1400
1070 INPUT "CONTINUE",T$
1075 GOTO 1025
1200 REM NEXT LEVEL
1205 PRINT "YOU ENTER THE TOWER."
1210 RETURN
1300 REM HAUTE
1305 H1 = H1 + 1
1310 IF H1 = 2 THEN H1 = 0
1315 IF H1 = O THEN PRINT "HAUTE IS NOW OFF."
1320 IF H1 = 1 THEN PRINT "HAUTE IS NOW ON."
1325 RETURN
1400 REM CAULDE
1405 C1 = C1 - 1
1410 C1 = ABS(C1)
1415 IF C1 = O THEN PRINT "CAULDE IS NOW OFF."
1420 IF C1 = 1 THEN PRINT "CAULDE IS NOW ON."
1425 RETURN
2000 REM BOTTOM OF THE TOWER
2010 T$ = "BOTTOM OF THE TOWER"
2015 D$ = "YOU ARE AT THE BOTTOM OF THE TOWER. THERE IS A DAGGER ON THE FLOOR, AND A SLIP OF PAPER UNDERNEATH IT."
2016 D$(LEN(D$)+1) = "THERE IS A GUARD ON THE STAIRS."
2020 GOSUB 32000
2025 PRINT "1) ATTACK GUARD"
2030 PRINT "2) GO UP STAIRS"
2035 PRINT "3) PICK UP PAPER"
2040 PRINT "4) PICK UP DAGGER"
2045 IF P2 = 1 THEN PRINT "5) READ PAPER"
2050 INPUT "CHOICE", Y
2055 IF Y = 1 THEN GOSUB 2500
2060 IF Y = 2 AND G2 = 0 THEN GOTO 2200
2065 IF Y = 2 THEN PRINT "THE GUARD BLOCKS YOUR ASCENT."
2070 IF Y = 3 THEN GOSUB 2300
2075 IF Y = 4 THEN GOSUB 2400
2080 IF Y = 5 AND P2 = 1 THEN PRINT "THE PAPER SAYS '1482'."
2085 INPUT "CONTINUE",T$
2090 GOTO 2025
2200 REM NEXT LEVEL
2205 PRINT "YOU ASCEND THE STAIRS."
2210 RETURN
2300 REM GET PAPER
2305 IF P2 = 1 THEN PRINT "YOU ALREADY HAVE THE PAPER."
2310 IF P2 = 1 THEN RETURN
2315 P2 = 1
2320 PRINT "YOU TAKE THE PAPER."
2325 RETURN
2400 REM GET DAGGER
2405 IF D2 = 1 THEN PRINT "YOU ALREADY HAVE THE DAGGER."
2410 IF D2 = 1 THEN RETURN
2415 D2 = 1
2420 PRINT "YOU TAKE THE DAGGER."
2425 RETURN
2500 REM ATTACK GUARD
2505 IF D2 = 0 THEN PRINT "THE GUARD KNOCKS YOU TO THE GROUND."
2510 IF D2 = 0 THEN RETURN
2515 G2 = 0
2520 PRINT "THE GUARD CRUMPLES TO THE FLOOR, FALLING ON THE DAGGER."
2525 RETURN
3000 REM MIDDLE OF THE TOWER
3010 T$ = "MIDDLE OF THE TOWER"
3015 D$ = "YOU ARE IN THE MIDDLE OF THE TOWER. THERE IS A KEY IN THE CORNER."
3016 D$(LEN(D$)+1) = "THERE ARE FOUR NUMBER DIALS ON THE DOOR TO THE NORTH."
3020 GOSUB 32000
3025 PRINT "1) PICK UP KEY"
3030 PRINT "2) OPEN DOOR"
3035 PRINT "3) ENTER COMBINATION"
3040 PRINT "4) ENTER ROOM"
3045 INPUT "CHOICE", Y
3050 IF Y = 1 THEN GOSUB 3200
3055 IF Y = 2 AND L3(1) = 1 AND L3(2) = 4 AND L3(3) = 8 AND L3(4) = 3 THEN GOSUB 3400
3060 IF Y = 2 AND D3 = 0 THEN PRINT "THE COMBINATION IS NOT CORRECT."
3065 IF Y = 3 THEN GOSUB 3300
3070 IF Y = 4 AND D3 = 1 THEN 3100
3075 IF Y = 4 THEN PRINT "THE DOOR IS CLOSED."
3080 INPUT "CONTINUE",T$
3085 GOTO 3025
3100 REM NEXT LEVEL
3105 PRINT "YOU ARE SO CLOSE..."
3110 RETURN
3200 REM GET KEY
3205 IF K3 = 1 THEN PRINT "YOU ALREADY HAVE THE KEY."
3210 IF K3 = 1 THEN RETURN
3215 K3 = 1
3220 PRINT "YOU TAKE THE KEY."
3225 RETURN
3300 REM ENTER COMBINATION
3305 INPUT "TURN FIRST DIAL TO", L3(1)
3310 PRINT "THE DIAL CLICKS."
3315 INPUT "TURN SECOND DIAL TO", L3(2)
3320 PRINT "THE DIAL WHIRRS."
3325 INPUT "TURN THE THIRD DIAL TO", L3(3)
3330 PRINT "THE DIAL SQUEAKS."
3335 INPUT "TURN THE FOURTH DIAL TO", L3(4)
3340 PRINT "THE DIAL WHINES."
3345 RETURN
3400 REM OPEN DOOR
3405 PRINT "THE DOOR OPENS."
3410 D3 = 1
3415 RETURN
4000 REM TOP OF THE TOWER
4010 T$ = "TOP OF THE TOWER"
4015 D$ = "YOU ARE AT THE TOP OF THE TOWER. THERE IS A DOOR TO THE NORTH."
4020 GOSUB 32000
4025 PRINT "1) UNLOCK THE DOOR"
4030 PRINT "2) ENTER THE CHAMBER."4035 INPUT "CHOICE", Y
4040 IF Y = 1 THEN GOSUB 4200
4045 IF Y = 2 AND D4 = 1 THEN 4100
4050 IF Y = 2 THEN PRINT "THE DOOR IS LOCKED."
4055 INPUT "CONTINUE",T$
4060 GOTO 4025
4100 REM NEXT LEVEL
4105 PRINT "YOU ENTER THE CHAMBER OF THE SLEEPING PRINCES..."
4110 RETURN
4200 REM UNLOCK DOOR
4205 IF K3 = 0 THEN PRINT "YOU DO NOT HAVE A KEY"
4210 IF K3 = 0 THEN RETURN
4215 IF D4 = 1 THEN PRINT "THE DOOR IS ALREADY UNLOCKED"
4220 IF D4 = 1 THEN RETURN
4225 D4 = 1
4230 PRINT "YOU PUSH THE KEY INTO THE DOOR AND IT SWINGS OPEN; YOU CAN SEE SHAPES SILHOUETTED IN THE MOONLIGHT."
4235 RETURN
Summary
This chapter has attempted to provide a reasonable introduction to programming the Apple I in BASIC. Particular emphasis has been placed on the peculiarities of the Apple I's version of BASIC. For more sample programs written in Apple I BASIC, visit the Apple I Owners Club on Applefritter. If you'd like a more in-depth guide to programming BASIC in general, most public libraries will have countless books on the subject.
← Previous | Contents | Next → |