ODD MAN REFORMS
Character redefinition techniques
Last month we described Odd Man Out, an educational game designed to help preschool children develop visual discrimination skills. This month, we will look at the initial stages of the program for Odd Man Out and the special features of the Atari computers that make the creation of the program so simple.
WHAT IS A CHARACTER?
The basis for Odd Man Out is the ability to easily redefine the Atari character set. Once this skill is mastered, the rest is easy, since most of the program involves the manipulation of characters to create desired displays. This may sound mysterious, but it is quite simple. With that in mind, let's look at how the Atari creates the characters of the alphabet.
Turn on your computer and examine the characters displayd on the screen. If you look closely, you'll see that each character is composed of a series of dots; every character in the Atari character set is defined by an eight-by-eight dot matrix. In terms of computer memory, each character is represented by eight bytes, one byte for each row of dots in the character.
The computer interprets each byte as a series of ones and zeros. If the individual bit is a one, the computer places a dot on the screen.
Suppose the value of one byte of a character is 24. This is stored in your computer as 00011000, since computers only recognize binary numbers. When your Atari encounters this byte, it interprets it by lighting dots that correspond to the 1's, which creates a pattern on the screen. A series of eight such bytes could create something like this:
Armed with this knowledge, we can begin to develop our own character set.
CONSTRUCTING A CUSTOM CHARACTER SET
Let's examine one of the objects to be displayed in level 1 of Odd Man Out. In order to make the objects large enough to be identified by young children, we decided to form each object by combining four characters in a two by two matrix.
The house is divided into four sections, with each section representing one character. Converting this picture into its numerical representation results in the following:
Upper left section -- 1,2,4,8,16,63,32
Upper right section - 128,64,32,16,8,4,252,4
Lower left section -- 32,32,35,34,34,34,34,63
Lower right section - 4,4,196,68,68,68,68,252
Each of the objects displayed in the first three levels of the game was created in this manner. We drew our characters by hand and calculated the proper numerical values ourselves, but several commercial products let you create your characters on the screen rather than on graph paper.
CHANGING CHARACTER SETS
The standard character set requires four pages of memory. (There are 128 characters in the set, each of which is represented by eight bytes. Each page of memory contains 256 bytes. Thus, 128 characters x eight bytes per character/256 bytes per page=four pages.)
Now that we have defined a new character set, we need to store it at the beginning of a memory page. To accomplish this, we can use memory location 106, which is the pointer to the top of RAM (Random Access Memory). There is no memory available at the page pointed to by location 106. Because of this, we can fool the computer into thinking there is less available memory by decreasing the value stored in this location. This is exactly what we will do. However, since the computer had been using the area at the top of memory to store display information, we will need to reassign this information. To do this, we need only issue a Graphics command. Thus, we can safely reserve the four pages of memory we need by using this three-step process:
1) RAMTOP = PEEK(1O6)
2) POKE 106; RAMTOP - 4
3) GRAPHICS 2 (or any valid graphics command)
After we have reserved this area, the next step is to place one character set into it. The easiest and most straightforward way to accomplish this is to POKE the new character set into the area with the following program:
10 GRTOP = (RAMTOP-4)*256
20 FOR I=0 TO 1023
30 READ X
40 POKE GRTOP+I,X
50 NEXT I
60 DATA ---------------------
This method is simple, but it has two majar disadvantages. Not only is it slow, but more importantly in order to use a number of custom character sets, as we will in this program, you need to POKE in a new character set every time you use it. So, let's look at another, more versatile method of storing our character sets.
VARIABLE AND ARRAY TABLES
The Atari keeps track of the variables that have been used in a program by means of a table that holds information on as many as 128 variables. This information consists of eight entries per variable. The first entry identifies the type of variable involved - string, array or numerical. The second entry is the variable number (the first variable in the table is number zero, the second number one, and so on). The third and fourth entries determine where the information in the variable is stored. The fifth and sixth entries form a sixteen-bit number that represents the dimensional length of the variable. The seventh and eighth entries also form a sixteen- bit number. This represents the in-use length of the variable. Thus, the variable table we're discussing looks like this:
VT+0----------Type of variable
VT+2----------Low order byte of the offset to the value of the variable
VT+3----------High order byte of the offset to the value of the variable
VT+4----------Low order byte of the dimensioned length of the variable
VT+5----------High order byte of the dimensioned length of the variable
VT+6----------Low order byte of the in-use length of the variable
VT+7----------High order byte of the in-use length of the variable
Once the variable table has been located, we are almost able to determine where a particular value is stored. Almost. The Atari stores the actual string data in another table, the array table. The values stored in locations VT + 3 and VT + 4 of the variable table are an offset from the start of the array table. In order to find the actual location of these values, we must find the beginning of the array table and apply the offset found in the variable table. This sounds complicated, but it isn't. Two memory locations hold the addresses of these tables. We can find the beginning of the variable table by using the following:
Similarly, we can find the beginning of the array table In this way:
We should now have enough information to store our custom character set.
CHARACTER SET MANIPULATIONS
To use our custom character set, we need to undertake the following steps:
1) Reserve memory space
2) Locate and modify the variable table
3) Place the new character set into memory
4) Change the character set pointer
We already know how to reserve space and locate the variable table; the next step is modification of the variable table.
In Odd Man Out, we will be using both the standard and custom character sets to form a modified character set. We will set up two string variables, RAM$ and ROM$. ROM$ will hold the standard character set, RAM$ the modified character set. It is important that RAM$ and ROM$ be the first two variables introduced in the program. This can be accomplished by using the following as the first program statement:
This way, we know that RAM$ and ROM$ will be the first two entries in the variable table.
Even though each character set contains 1024 entries, we have purposely dimensioned these two variables to have length one, because we are going to reassign the memory locations to store this information. Had we dimensioned both variables to be 1,024 characters long, BASIC would have reserved 1024 bytes of memory for each variable in the array table. Since this offset is not where we want those values to be stored, 2K of RAM would have been wasted. By using the above method, however, only two bytes of RAM will not be used. Now, let's make the variable table modifications.
We want to store the modified character set in the four pages of reserved memory. To do this, we need to modify the address, dimensioned length, and in-use length of the RAM$ in the variable table. Listing 1 will accomplish this.
Let's look at what this listing does. Line 10 introduces RAM$ and ROM$ and ensures that they are the first two entries in the variable table. Line 20 reserves four pages of memory for the character set. The graphics command in line 30 moves the display information out of this reserved area. Line 40 finds the locations of the variable and array tables. Line 50 converts the page number to the memory location for the start of the character set. Line 60 calculates the offset from the start of the character set to the start of the array table. This is the value that will be stored in locations two and three of the variable table. Lines 70 and 80 convert the length and offset from a decimal to a two-byte representation. Due to a bug in Atari BASIC, it is necessary to dimension the string variable to 1025 instead of 1024. Lines 90, 100, and 110 store the offset, dimensioned, and in-use lengths into the variable table.
Type in Listing 1 and RUN it. When the computer prints READY, type: PRINT LEN(RAM$). The computer should respond: 1025. Thus, even though we dimensioned RAM$ to be one character long, because we changed the variable table the computer thinks RAM$ is 1025 characters in length.
The modification for R0M$ is similar; the only change required is: OFFROM = 57344-AT. (57344 is the start of the ROM character set.) Now we are ready to read the new character set into memory.
Since we have stored the existing and modified character sets in string variables, we will use string variables to store the custom character set we have created. This will allow us to change the modified character set by simple string variable assignments. We also will set up three string variables to hold the redefined characters used in the first three levels: OBJECT$, GEO$, and E$. As a result, at the beginning of the program we call read in all the data for the redefined characters and store it in these string variables. The creation of the modified character set required for a particular level of the game will then involve only a few string variable assignment statements. Because of this, character set modifications can be accompllshecl very rapidly.
The Atari already has a character set stored in ROM (Read Only Memory) that displays normal text and graphics characters. When you change text modes from Graphics 0 to Graphics 1 or 2, you can access only one half of this character set. Memory location 756 serves as a pointer to the beginning of the half of the character set in use. As a result, by changing the value stored in location 756, you can change the characters used by the computer. To display lower case letters and graphics characters, you POKE 756,226. Capital letters and punctuation characters can be displayed by POKEing 756,224 (the values 226 and 224 are the page numbers that contain the start of the character set). We can also change the value stored in location 756 so that it points to the start of our custom character set.
Now, we are ready to put theory into practice. The program in Listing 2 reserves space for the modified character set (lines 20 to 200). The variable table (lines 340 to 540) reads in the redefined characters (lines 580 to 680), and displays four objects on the screen at a time (lines 1460 to 1880). To change the display, press [RETURN]. This program is the heart of Odd Man Out.
This completes our introduction of the Atari character sets. No other microcomputer allows character sets to be manipulated so quickly and easily from BASIC.
There will be two more installments of code to complete the game. Once you have Listing 2 typed in and debugged, save it so you can add the next portion of the program next month. In our next article, we will look at joystick routines and character animation.