5

Fontbyter

titlebar.gif

Orson Scott Card and Carl Zahrt


"Fontbyter" is a utility which makes creating graphics displays in ANTIC modes 4 and 5 both easy and fun. Fontbyter requires a minimum of 40K memory.

It's hard to tell, when you're using "Fontbyter," whether this is a utility or a game. You can easily create graphics displays many times the size of the screen and save them to disk, using the ROM character set--or character sets you have designed yourself. And because Fontbyter allows you to use two "hidden" character modes, ANTIC modes 4 and 5, you get all the high-resolution color of GRAPHICS 7 with the convenience and memory usage of GRAPHICS 0.

Once you have a character set designed and a picture drawn on the screen, changing an 8-by-8-pixel character block takes only one POKE. This allows easy, almost instant animation; your programs can be shorter than they would be if you tried to get the same effect with GRAPHICS 7; and you have more memory available to you because the screen displays take up less room.

The problem is creating the actual display. In ANTIC 4, you have 24 lines of 40 characters; in ANTIC 5,12 lines of 40 characters. Laying out the screen display and writing the DATA statements can be a long, tedious, painful process. You have to remember what each character looks like and make sure that the characters are in the right order in the DATA statements you create. And when you want to change a display, you have to go back and find the right DATA statement and alter it.

Fontbyter lets you create and edit in ANTIC 4 or 5 right on the screen. You don't have to write down the number of the character and POKE it into memory; you only have to press a key or combination of keys, and your character will be displayed exactly where you want it on the screen. Simple commands allow you to fill large areas with a single character, insert or delete lines, scroll around the screen to view large areas quickly, or change the colors on the screen. And Fontbyter will scroll horizontally and vertically, so you can use the screen as a window onto a very large display--up to 4K.

Best of all, you can save your screen to disk at any point and return to continue editing it. Using a simple subroutine, you can then load your screen into memory in your own program. The first eight bytes of every file Fontbyter creates contain the mode number, the display width, the display height, and the five colors of the screen display.


Starting Fontbyter

Character Set. When you RUN Fontbyter, the program accesses your disk and shows you a directory of all the files with the filetype ".SET". Fontbyter assumes that these are all character sets. The program then asks you to choose which one you want to use. Or, if you wish to use the built-in ROM character set, enter the character @ as the filename.

There is only one custom character set included with Fontbyter, but by using a character editor you can create as many different sets as you want. There are several character editor programs that will help you create your own character sets, including Tim Kilby's ANTIC 4 and 5 character editor in the December 1982 BYTE (reprinted in this book by permission of the author) and Charles Brannon's "SuperFont" from COMPUTE!'s First Book of Atari Graphics.

Any character editor can be used if you remember that instead of an 8-byte by 8-bit grid, each character is drawn on an 8-byte by 4-bit-pairgrid. A bit-pair of 00 selects the background color (register 4), and bit-pairs of 01, 10, and 11 select color registers 0, 1, and 2. Bit-pair 11, in inverse mode, selects register 3.

If the character set you ask for is not on the disk in drive 1, the program will prompt you either to insert the correct disk or to ask for a different set. Whenever Fontbyter asks you for a filename, you don't need to enter more than the eight-character name--Fontbyter always supplies the device name "D1:" and the extender ".SET" or ".SCR". If you use an illegal name, Fontbyter will ask you to try again.

Screen files. When you have chosen your character set, Fontbyter displays a directory of all the files with the filetype ".SCR". Fontbyter assumes that these files contain screen displays created and saved by Fontbyter. If no directory is displayed, it means that there are no files with the filetype ".SCR" on the disk.

At the end of the directory, you will be told the number of sectors left on the disk. Be sure that the disk you use for saving screens has enough room for the screen you intend to save. A maximum-size display is almost 4K, which will create a file of 33 sectors. Disks can fill up pretty fast at that rate.

Save file. The program asks you what name your saved screen file should have. When you are through editing and want to save your finished screen, this is the filename that Fontbyter will use to create the save file. You can use a filename that you used before, but saving the new file will erase the old one. Again, only the eight-letter filename is necessary. Fontbyter automatically selects "D1:" as the device name and ".SCR" as the filetype.

Load file. The program asks you if you want to edit a screen that was previously saved. If you do, you will be asked the name of the file you want to load from. (Again, only the eight-letter name will be used--the filetype must be ".SCR".) If the file is not found, Fontbyter will ask you either to enter another name or to insert the disk with that file on it; if you choose to enter another name, Fontbyter goes back to the original load file prompt, and you can decide at that point not to edit a previously saved file after all.

Notice that this system allows you to load from a file and then save your edited version back to the same file, erasing the old version; or you can choose to save the file under a different filename, so that both versions will exist. There is an added safeguard, too. When you save the screen display, it is first saved under the name "D1:TEMPFILE.SCR". Then Fontbyter asks you if you want to save it under the name you chose at the beginning of the program. If you change your mind about the save filename then, you can exit Fontbyter and use DOS to change "D:TEMPFILE.SCR" to whatever name you want.

Load file parameters. If your load file is found, Fontbyter immediately opens it and reads the first three bytes. Then it reminds you of the ANTIC mode, width (in characters), and height (in lines) of the file as it was saved. If you don't want to change those parameters, you can proceed directly to the final check; if you do want to change them, Fontbyter will ask you to choose the mode, width, and height of the file as if you were creating a new screen.

Changing the height or mode is fairly safe. Mode changes put twice as many lines on the screen, but all the relationships are the same. Changing the height merely adds or subtracts lines at the bottom of the display. Remember, though, that changing the width of a file will have very odd results. It does not cut off the edges of the old screen--it merely causes the lines to wrap around at a different point, so that nothing fits together vertically the way that it did.

ANTIC mode. Fontbyter asks you to choose which ANTIC mode you want. The only choices are 2 (GRAPHICS 0), 4, or 5. Mode 4 has shorter, squarer characters, and fits 24 lines on a screen. Mode 5 has tall, thin characters and fits only 12 lines on a screen. This means that a display file a hundred lines from top to bottom will give you more than eight distinct screen displays in ANTIC 5, but only just over four distinct displays in ANTIC 4. ANTIC 2 (GRAPHICS 0) is included, even though it is not a four-color mode, so that you can use Fontbyter to create displays using the built-in ROM character set.

Display width. The minimum width of a line is 40 characters. If you enter a number less than 40, Fontbyter will change it to 40. The maximum width depends on the mode. The limiting factor here is that all screen displays must fit within 4K. Because of this, the wider a screen display you choose, the fewer vertical lines you can have. You cannot have a line so wide that it would not allow the minimum number of lines. Since you will not be allowed any fewer than 24 screen lines in ANTIC 2 or 4, you naturally can't have as wide a screen as in mode 5, which has a minimum of 12 lines per screen.

Display height. The minimum height, in number of lines, is 12 lines for ANTIC 5 and 24 lines for ANTIC 2 and 4. The maximum height depends on the line width you chose. If you ask for more lines than the allowable maximum, Fontbyter will change the figure to the maximum.

Final check. Fontbyter clears the screen and then displays what your choices were: the character set, the file in which to save your screen, the file (if any) to load from, the mode, the width (in characters), and the height (in lines). If you want to make any changes, press OPTION. If you are satisfied with your choices, press START.

Fontbyter will display a wait message for a few moments, and then the screen will go completely blank. This is so the setup operations will run faster. When Fontbyter is ready to go on--and it won't be long--either the load screen you asked for will appear or a cursor will appear in the upper-left-hand corner of a blank screen. The cursor is whatever the ESCAPE character looks like in the character set you chose.

Also, part of the character set will be displayed on the bottom four lines of the screen. The characters are arranged in the same order as the computer keyboard, so that you can easily figure out which key to press in order to display a particular character.


Editing Features

To use the keyboard. The character set is divided into three groups: regular, shifted, and control. You can change from one to another using the CAPS/LOWR key. To get the regular character group, press CAPS/LOWR. To get the shifted character group, press SHIFT and CAPS/LOWR at the same time. To get the control character group, press CONTROL and CAPS/LOWR at the same time. As soon as you make the change, the character keyboard display at the bottom of the screen will change to show you the characters now available.

Instead of the usual computer keyboard system of locking only the alphabetic keys into shifted and control functions, Fontbyter shifts the entire keyboard. After you press SHIFT and CAPS/LOWR, you can press any key on the keyboard and get the shifted character--without pressing SHIFT again. The same applies to CONTROL with CAPS/LOWR.

Some keys, of course, don't have a shifted or control value (ESC, DEL, and RETURN, for instance), and others usually display only the inverse of another character (SHIFT-TAB, for instance). Since these don't display a separate character, pressing them only produces the same character that you would get if you pressed the space bar--a blank. (If your character set redefines the space bar character, that character will fill your display when it first comes up, and will appear on the screen whenever you enter a nonprinting character.)

The keys do not produce their normal clicking sound, except for the command keys, which are described next.

Command keys. No matter which character group you are using, there are some key combinations that Fontbyter interprets as commands. Pressing INSERT and SHIFT together will insert a blank line on the screen. Pressing DELETE and SHIFT together will delete a line. Pressing CONTROL and an ARROW key together will cause the cursor to move.

Remember, to print the character represented by the CONTROL-ARROW combination, press only the ARROW key while the control group is locked in. To move the cursor, press CONTROL and ARROW at the same time, regardless of which group is locked in.

Inverse video (Atari logo) key. This key is a toggle. Pressing it shifts you back and forth between inverse and regular video. In ANTIC 2 (GRAPHICS 0), this will cause all the characters you enter to be reversed, as the computer normally does. In ANTIC 4 and 5, however, this will cause Color 3 to take its value from color register 4 (memory location 711 instead of 710). It will affect, therefore, only one of the colors, and if a character does not contain any dots of Color 3, inverse mode won't have any effect at all.

CONTROL-ESC. This key combination is a toggle. Pressing it will shift you back and forth between Still and Auto-Advance modes. In Still Mode, pressing noncommand keys will display a new character in the same place on the screen. In Auto-Advance Mode, pressing noncommand keys will display a new character and then advance the cursor to the next position to the right, unless doing so would take the cursor beyond the edge of the display.

To move the cursor. Either move the joystick in the direction you want to move, or press the appropriate CONTROL-ARROW key combination. Only the joystick allows diagonal movement.

When the cursor reaches the edge of the screen, the display will begin to scroll until it reaches the limits of display height and width you specified during start-up. If you are at the edge of the display, the cursor simply won't move any farther that direction.

Fast-fill function. Sometimes you will have large areas or lines to fill with the same character. Instead of entering the character by typing it in each space where it is to appear, you can use the joystick and fire button. First maneuver the cursor until it is on top of the character you want to copy, or move it to the place where you want to begin the fast-fill operation and enter the character from the keyboard. Then press down the joystick button and hold it down while you use the joystick to move the cursor. From then on, until you let up on the button, wherever you move the cursor using the joystick, a trail made up of that character will be left behind.

You can also use this function to erase areas of the screen fairly quickly. Just move the cursor to a blank, press down the button, and the cursor will leave blanks behind it wherever you make it go.

Clear screen function. To erase the entire display, press CONTROL-SHIFT-CLEAR.

Delete line function. To delete an entire line of your screen, move your cursor to the line you want to delete and press SHIFT-DELETE. The line will vanish, and the entire display below that line will move upward one line on the screen. Whether the very bottom of your display is visible on the screen or not, a line of blanks will be inserted as the last line in your display.

Insert line function. To insert a blank line in your display, move the cursor to the position where you want the new line. Then press SHIFT-INSERT. The line that the cursor was on will move down, as will all the other lines below it in the display, and the cursor will now be on a blank line. At the bottom of the display, whether it is visible on the screen or not, the last line of your display will be deleted completely.

With both the delete and insert line functions, the line that disappears is irrecoverably lost. To get it back, you will have to enter all the characters just as you did before. So be careful about using these two functions!

By using the delete and insert functions in succession, you can quickly blank large areas of the screen, a line at a time. Simply move to the top of the area you want to blank out, and press SHIFT-DELETE as often as it takes to erase all the lines you wanted to get rid of. Then press SHIFT-INSERT until the desired number of blank lines appears.

You can also use these functions to move the entire picture upward or downward in the display. For instance, suppose you loaded a display that had been created and saved with only 24 lines, and you want to add another 24-line picture above it. At the beginning of the editing session, simply specify 48 lines as the height of the display. Fontbyter will put the 24 new blank lines at the end of the display. To move the old picture down into that blank area, start at the top of the screen and press SHIFT-INSERT 24 times.

Three joystick modes. We've already gone over the use of the joystick in Cursor Mode. The joystick can also be toggled into two other modes. If you press the START button while in Cursor Mode, the joystick will change to Scroll Mode. If you press the START button in Scroll Mode, the joystick will shift to Color Mode. And pressing the START button in Color Mode will shift you back to Cursor Mode again.

1. Scroll Mode. This mode enables you to scroll the TV screen window around the entire display by moving the joystick in the appropriate direction. When you move, the cursor character will disappear. When you return to Cursor Mode, the cursor will come back to the middle of the screen.

2. Color Mode. In this mode, the joystick controls the color registers as follows:

As you press the joystick forward or to the right in Color Mode, that particular color will get brighter and brighter until it reaches maximum brightness; then it will jump to the next color at its darkest value and get brighter and brighter with that color. Pushing left or back cycles through the colors from bright to dark. There are 16 colors, each with eight levels of brightness. You can cycle through the colors endlessly in either direction.

When you start editing with a new display, the colors are the system default colors. When you load a previously saved display, however, you start with the colors saved with that display. You can change the colors however you like, and whatever the colors are when you save your display, those values will be saved with it.


Summary of Command Keys

Command Key
START

SELECT




OPTION

CONTROL-ARROW
SHIFT-INSERT

SHIFT-DELETE

Atari logo key

SHIFT-CAPS/LOWR
CONTROL-CAPS/ LOWR
CONTROL-ESC

CONTROL- SHIFT-CLEAR
Description
Cycle from Cursor Mode to Scroll Mode
to Color Mode and back to Cursor Mode.
Save the current display without inter-
rupting the edit. In Color Mode, moving
the joystick forward and back with
SELECT pressed will change the inverse
color.
Save the current display and stop the
editing session.
Move the cursor.
Insert a blank line where the cursor is and
delete the bottom line of the display.
Delete the cursor line and add a blank line
at the bottom of the display.
Toggle back and forth between inverse
and regular characters.
Select the shifted character group.
Select the control character group.
Toggle between Still and Auto-Advance
modes.
Erase the entire display.

Ending and Saving

There are two ways to save a screen.

1. You can press the SELECT button when the joystick is in Cursor Mode, and the display will be saved as "D1: TEMPFILE.SCR". The screen is not changed, and you can resume editing as soon as the joystick or keyboard responds again.

2. You can press the OPTION button. Fontbyter will save the entire display in a file named "D1:TEMPFILE.SCR". The screen then clears, and Fontbyter asks if you want to save the display in the save file you asked for at the beginning of the edit. If you answer yes, "TEMPFILE" is renamed with the save filename you chose at the beginning. If a file with the same name already exists on the disk, it will be erased at this time.

If you are merely saving a half-done file to make sure some catastrophe doesn't lose it for you, then "TEMPFILE.SCR" should be security enough--if the system crashes, you'll know that the screen as you last saved it is in that file.

You will then be asked if you want to return to edit the same screen. If you say yes, your saved screen will quickly be reloaded into memory, and the program will reinitialize. If you say no, you will be asked whether you want to quit or start Fontbyter over again. If you choose the quit option and change your mind, don't worry. Just give the direct command RUN, and Fontbyter will begin again with the setup prompts.


Using Fontbyter Screens in Your Programs

Just because Fontbyter scrolls doesn't mean you have to make one continuous scrolling display. You can create many different screen displays in one file, "stacking" them vertically, and then use page flipping in your own program to move instantly from one to another. The advantage of using Fontbyter is that while you are creating the screen displays, you can scroll from one to the other to compare them and make sure that any animation effects you are trying for are working properly.

The diagrams will show you the variety of display configurations you can choose.

Figure 1 is the simplest and smallest display--just enter the minimum height and width for the mode you're working in.

Figure 2 is a completely horizontal display. You might want such a display in a game program to provide a very wide scramble-type game playfield, or in a storytelling program to allow the story to progress from left to right.

To get the widest possible display, use ANTIC 5. This allows displays that are 8.5 screens wide. However, the characters in ANTIC 5 are twice as tall as in ANTIC 4, which can distort your display.

If you want even wider displays, you can chain several displays together by beginning one display with the exact picture that ends the previous one; from there, continue the display as if there were no break. Then, when your own program scrolls to the end of one, it can page flip to the next 4K block of memory, where the next display begins, and continue scrolling. If you are doing horizontal scrolling, however, you are undoubtedly revising your display list in machine language, and the page flip will have to be in machine language, too. You can even make two displays chain to each other by having Display 1 begin with the end of Display 2, and Display 2 begin with the end of Display 1. That way the user keeps cycling through the same endless loop.

Figure 3 is a completely vertical display. You can use the same techniques to scroll vertically through a continuous display, except that now, since you are doing no horizontal scrolling, you can do scrolling and page flipping from BASIC just by POKEing new values into bytes 4 and 5 (counting from 0) of the display list.

In Figure 4, the screen is a window into a display that extends some distance both horizontally and vertically. You could use this in your programs to allow users to explore a map, or find their way out of a maze, or control hundreds of armies in a really massive and complex full-color war game, or simply to admire an elaborate picture.


chap5p1a.gif
chap5p1b.gif

Programming with Fontbyter

Here are subroutines you can include in your own programs to use displays you have created with Fontbyter.

Loading files. To use Fontbyter displays, your program will need to load a character set and the display file. Subroutine 1 loads slowly, entirely from BASIC. Subroutine 2 loads quickly, using a machine language routine that accesses an operating system fast load program.


Subroutine 1. Slow Load

Download P130L1.BAS (Saved BASIC)
Download / View P130L1.LST (Listed BASIC)

Subroutine 2. Fast Load

Download P130L2.BAS (Saved BASIC)
Download / View P130L2.LST (Listed BASIC)

Display list setup. Subroutine 3 sets up an ANTIC 2 or 4 display list that can be horizontally or vertically scrolled. Subroutine 4 sets up an ANTIC 5 display list that can be horizontally or vertically scrolled. Subroutines 5 and 6 set up display lists that cannot be horizontally scrolled--use these only to load displays that were created with the minimum line width.

Subroutine 3. Horizontal Scroll Display List, ANTIC 2 or 4

Download P131L3.BAS (Saved BASIC)
Download / View P131L3.LST (Listed BASIC)

Subroutine 4. Horizontal Scroll Display List, ANTIC 5

Download P131L4.BAS (Saved BASIC)
Download / View P131L4.LST (Listed BASIC)

Subroutine 5. Regular Display List, ANTIC 2 or 4

Download P132L5.BAS (Saved BASIC)
Download / View P132L5.LST (Listed BASIC)

Subroutine 6. Regular Display List, ANTIC 5

Download P132L6.BAS (Saved BASIC)
Download / View P132L6.LST (Listed BASIC)

These routines use the following variables:

TOP is the page number of the top of memory. The Atari will not touch anything located above the top of memory--but anything below it is fair game. The display list, character set, screen memory, and machine language routines should all be placed above SP. So the load routines find out where the top of memory is and move it down enough pages to leave room for all the protected program areas. SC is the absolute address of the top of memory (SP*256); it is also the start of screen memory, so that it is POKEd into both the display list and location 106.

How much room should you leave? The character set takes 1K (four pages) and must start on a 1K boundary. Screen memory will never take more than 4K (16 pages), and should start on a 4K boundary, since ANTIC has problems when screen memory crosses that line. If your display is less than 2K, you can probably skip back from the top of memory a mere 4K (16 pages, or PEEK(106)-16), place screen memory at the new top of memory, and put the display list, machine language routines, and character set above it. If your display list is 3K or more, you should probably skip back 6K (24 pages, or PEEK(106)-24), place the character set at the new top of memory, followed by the display list, machine language subroutines, and then screen memory beginning at the 4K boundary line, 16 pages before the old top of memory. This routine assumes that arrangement.

SP is the page number of the start of screen memory, and SC is the absolute address of the start of screen memory (SP*256).

DL is the start of the display list. For page flipping, DL3 is DL+3, and DL4 is DL+4. These will contain the low byte and high byte of screen memory, and POKEing new values into these locations will flip screen memory.

CHBAS is the page number of the character set, and CH is the absolute address (CHBAS*256).

MODE is the ANTIC mode number--either 2, 4, or 5. Adding 64 to MODE each time it is POKEd in tells the computer to look for a new screen memory address in the next two bytes in the display list.

WIDE is the width, in characters, of the entire horizontal line, not just the 40-character portion visible on screen at any one time. Thus, every MODE instruction is followed by a two-byte address, C, which tells it where to find the start of the next horizontal line.

POKEing 560 and 561 with 0 and DL/256 is what actually makes the display list start working. Until that moment, the display list is just a series of numbers in memory. But once 560 and 561 contain the address of the start of your display list, the TV screen is under your program's control.

ICBADR, ICBLEN, and ICCOM are the addresses of key locations in the IOCB handler. ICCOM must contain the number of the operation to be performed (7 to load, 11 to save). ICBADR must contain the low byte of the starting address of the area in memory to be saved from or loaded to (ICBADR+1 will contain the high byte). ICBLEN must contain the low byte of the length of the file to load (ICBLEN+1 will contain the high byte). The variable X represents the offset into the IOCB area. If you OPEN #1, then X=16. If you OPEN #2, then X=32. And so on, in multiples of 16. You might not get good results using OPEN #0 or OPEN #6--those are reserved for system use.

With screen files created by Fontbyter, remember that the first eight bytes always contain the following information:

To calculate the number of bytes in the whole screen display (SZ), multiply the height by the width. The number of bytes in the file is that number plus eight.


Typing the Program

The bulk of the program is written in BASIC. The shortest machine language routines are included as string constants. The longer routines, however, DISPLAY, EXPAND, and DELETE, and two data files, MENU.DAT and CHARDATA.DAT, are listed after the main program. These should be entered using the BASIC loader program provided and saved on disk with exactly the filename specified. Fontbyter will look for these files and load them into strings or particular areas of memory during the run of the program.

Since Fontbyter works most efficiently with a disk drive, the program as written assumes a disk drive. However, a patient cassette user can remove all the routines related to choosing and testing filenames, and simply assign the value "C:" to all filename variables. You may also want to add prompts to tell the user what file the program is asking for. (The biggest problem arises with load files during initialization, when the program tests the saved screen file once, then loads it again later. If you decide not to revise the program, make sure that you rewind the cassette containing the screen file after that initial test, so the file will be complete when it is loaded by the screen load subroutine.)

There are no REM statements in Fontbyter. Instead, remarks are included as typeset lines that interrupt the program listing. Type only the numbered program lines that were printed out by a printer, not the comments printed in the same typeface you are reading now.


Program 1. Fontbyter

Download FONTBYTE.BAS (Saved BASIC)
Download / View FONTBYTE.LST (Listed BASIC)

Start-up. DIMension arrays and string variables; clear the screen; establish key addresses.

Line 5. F$ is the character set name; FSAVE$ is the save filename; FLOAD$ is the load filename; FL$ and FLL$ are temporary filenames for various uses; DELETE$ and EXPAND$ will hold machine language subroutines in ASCII form; C(n) will hold the relationship between keyboard code and internal code.

10. Clear the screen. ICCOM, ICBADR, and ICBLEN are addresses in Input/Output Control Block (IOCB) zero (for files opened as #0). ICCOM is the address where the command should be POKEd; ICBADR should be POKEd with the low byte of the address in memory where files should be stored or loaded (ICBADR+1 holds the high byte); ICBLEN should be POKEd with the low byte of the length of the file to be moved (ICBLEN+1 holds the high byte). X is the offset into succeeding IOCBs. To use file #1, X=16; for file #2, X=32; and so on.

15. COL1 through COL5 are the addresses of the color registers. COL4 is the inverse mode color; COL5 is the background color. SHIF keeps track of which character mode we are locked into--unshifted (0), shifted (64), control (128), or shift-control (192). SCON is the value to turn the screen back on. POKE 16,112 disables the BREAK key. Jump to 440.

5 DIM F$(20),FSAVE$(20),FLOAD$(20),FL$(40),FLL$(20),DELETE$(124),
   EXPAND$(124),CLEAR$(33),C(255) 
10 GRAPHICS 0:X=16:ICCOM=834:ICBADR=836:ICBLEN=840
15 COL1=708:COL2=709:COL3=710:COL4=711:COL5=712:SHIF=64: SCON=PEEK(559):
   POKE 16,112:GOTO 440

Display Load Subroutine. MD is the mode number; WD is the number of characters per line; LN is the number of lines in the display. If the width of the screen is greater than 255, the high byte of the width has been stored in MD by adding 10 to the mode number. The size of the display is (adjusted) WD*LN. The colors are read; then ICBADR is POKEd with the starting address of screen memory; ICBLEN is POKEd with the length of the remainder of the file; and ICCOM is POKEd with 7, which is the read-from-disk command. The machine language subroutine merely pulls three numbers off the stack and jumps to a subroutine built into the operating system.

20 OPEN #1,4,0,FL$:GET #1,MD:GET #1,WD: GET #1,LN:
   IF MD>5 THEN WD=WD+256:MD=MD-10 
25 SZ=WD*LN: FOR I=COL1 TO COL5: GET #1,N:POKE I,N:NEXT I
30 SC=SP*256: POKE ICBADR+X+1,SP:POKE ICBADR+X,0:
   POKE ICBLEN+X+1,1+INT(SZ/256):POKE ICBLEN+X,0
35 POKE ICCOM+X,7:I=USR(ADR("hhh{inverse asterisk}LV{inverse small d}"),X):
   CLOSE #I: RETURN

Display Save Subroutine. The Display Load Subroutine in reverse. ICCOM is now POKEd with 11, the write-to-disk command. This is where the program adds 10 to MD if WD is greater than 255. The filename is always "D1:TEMPFILE.SCR".

40 OPEN #1,8,0,"D1:TEMPFILE.SCR":WD=WIDE:MD=MODE:
   IF WIDE>255 THEN WD=WIDE-256:MD=MODE+10
45 PUT #1,MD:PUT #1,WD:PUT #1,LINE:FOR I=COL1 TO COL5:
   PUT #1,PEEK(I): NEXT I 
50 POKE ICBADR+X+1,SP:POKE ICBADR+X,0:
   POKE ICBLEN+X+1,1+INT((LINE*WIDE)/256):POKE ICBLEN+X,0 
55 POKE ICCOM+X,11:
   I=USR(ADR("hhh{inverse asterisk}LV{inverse small d}"),X):
   CLOSE #I: RETURN

Delete Line Subroutine. Line 60 quits the routine if the cursor is on the bottom line of the display. LOWAD is the address of the leftmost character on the cursor line; HIADD is the line below it on the screen (which is above it in memory). LOWAD is POKEd into 203-204, and HIADD into 205-206. Address 207 is POKEd with the number of lines between the cursor line and the end of the display, and 208 and 209 hold the low and high bytes of the width of a line. The machine language subroutine in the string DELETE$ moves everything below the cursor line up one line on the screen, and inserts a blank line at the bottom of the display. The cursor (91 = ESC) is then POKEd back into place.

60 IF ((LINE*WIDE-PIX)<WIDE) THEN RETURN
65 LOWAD=SC+WIDE*INT(PIX/WIDE)-1:HIADD=LOWAD+WIDE:
   POKE 206,INT(HIADD/256):POKE 205,HIADD-PEEK(206)*256 
70 POKE 204,INT(LOWAD/256):POKE 203,LOWAD-PEEK(204)*256:POKE SC+PIX,OLD 
75 POKE 207,INT((LINE*WIDE-PIX)/WIDE):POKE 208,WLO: POKE 209,WHI 
80 C=USR(ADR(DELETE$))
85 OLD=PEEK(SC+PIX): POKE SC+PIX,91:RETURN

Insert Line Subroutine. The same as the Delete Line Subroutine, except that everything from the cursor line to the end of the display is moved down the screen, and a blank line is inserted at the cursor line. LOWAD is now the second to last line of the display, and HIADD is the last line of the display.

90 IF ((LINE*WIDE-PIX)<WIDE) THEN RETURN
95 HIADD=SC+WIDE*(LINE-1)-1:LOWAD=HIADD-WIDE:
   POKE 206,INT(HIADD/256):POKE 205,HIADD-PEEK(206)*256 
100 POKE 204,INT(LOWAD/256):POKE 203,LOWAD-PEEK(204)*256:
    POKE SC+PIX,OLD
105 POKE 207,INT((LINE*WIDE-PIX)/WIDE):POKE 208,WLO:POKE 209,WHI
110 C=USR(ADR(EXPAND$))
115 OLD=0: POKE SC+PIX,91:RETURN

Main Loop. Most of the time, the program cycles through from line 125 to line 150; unless the user presses a key or moves the joystick, this will go on endlessly.

120. Store the value of whatever character belongs in screen memory where the cursor now is in the variable OLD. When the cursor moves off, OLD will be POKEd back in. The internal code for the ESC character is 91--it is used as the cursor. POKE 559,SCON turns the screen on. This line is executed only once.

125. Zero out several variables and check for user input. OPT holds the value returned by the console keys, DI the value returned by joystick 1, and T the value of fire button 1.

130. If the START button is pressed, jump to the Quick Scroll Subroutine at 870; when that is over, jump to the Color Change Subroutine at 255.

135. If the joystick has been pushed, jump to the Cursor Movement Subroutine at 155.

140. If a key has been pressed (PEEK(753)=3), jump to the Read Keyboard Subroutine at 220. Upon RETURNing, the flag MV will tell whether the arrow keys or auto-advance mode were used to move the cursor; if yes (MV = 1), jump to the third line of the Cursor Movement Subroutine at 165.

145. If OPTION has been pressed, jump to the Stop Edit Subroutine at 705. If SELECT has been pressed, jump to the Display Save Subroutine. The display will be saved as "D1:TEMPFILE.SCR" without interrupting the edit.

150. Start the loop over again.

120 OLD=PEEK(SC+PIX):POKE SC+PIX,91:POKE 559,SCON:POKE 16,112
125 MV=0:V=0:H=0:OPT=PEEK(53279):DI=PEEK(632):T=PEEK(644):E=0
130 IF OPT=6 THEN GOSUB 870: GOSUB 260:GOTO 125
135 IF DI<15 THEN GOSUB 155:GOTO 125
140 IF PEEK(753)=3 THEN GOSUB 220:ON NV GOSUB 165: GOTO 125
145 ON OPT=3 GOTO 705:IF OPT=5 THEN GOSUB 40: POKE SC+PIX,91:GOTO 125
150 GOTO 125

Cursor Movement Subroutine. In this routine, V is vertical movement; H is horizontal movement; PIX is the current position of the cursor relative to the start of screen memory; OLD is the character "under" the cursor in screen memory; UD is the current cursor line; LR is the current left-right position of the cursor on a line; W is the position of the upper-left-hand corner of the current screen display relative to the start of screen memory; U is the current line number of W; and L is the current left-right position of W on its line. WH is the horizontal scroll flag (1 = left, 2 = right); WV is the vertical scroll flag (1 = up, 2 = down).

155-160. Convert the joystick position into cursor move instructions.

165-175. Get the current cursor position. If the called-for movement would take the cursor beyond the edge of the display, cancel that movement instruction. If no movement is called for, quit the subroutine. Keyboard-controlled cursor movements enter the routine here.

180-195. Get the current screen position relative to the start of screen memory. If scrolling is necessary, execute the machine language scroll subroutine at address DISPLAY.

200. Put the OLD character into PIX; change PIX to its new value; sound the console buzzer (POKE 53279, 1).

205-215. If the trigger is not pressed, put the character at PIX in the variable OLD and POKE the cursor character into the new cursor position.

155 V=WIDE*((DI=9 OR DI=13 OR DI=5)-(DI=10 OR DI=14 OR DI=6)):POKE 77,0
160 H=(DI=6 OR DI=7 OR DI=5)-(DI=10 OR DI=11 OR DI=9)
165 UD=INT(PIX/WIDE):IF UD-(V<0)<0 OR UD+(V>0)=LINE THEN V=0
170 LR=PIX-WIDE*UD:IF LR+H<0 OR LR+H>WIDE-1 THEN H=0
175 IF H=0 AND V=0 THEN 215
180 WH=0:WV=0:W=PEEK(DL4)+256*PEEK(DL5)-SC
185 U=INT(W/WIDE):IF V<>0 THEN WV=(UD-U-(V<0)<0)+2*(UD-U+(V>0)>8+12* (MODE<>5))
190 IF H<>0 THEN L=W-U*WIDE:WH=(LR+H-L<0)+2*(LR+H-L>39)
195 IF WH>0 OR WV>0 THEN POKE DL+114,WH: POKE DL+115,WV:C=USR(DISPLAY)
200 POKE SC+PIX,OLD:PIX=PIX+H+V:POKE 53279,1 
205 IF T=1 THEN OLD=PEEK(SC+PIX):POKE SC+PIX,91:GOTO 215 
210 POKE SC+PIX,OLD 
215 RETURN

Read Keyboard Subroutine. C is the actual value of the key combination pressed (key plus SHIFT and/or CONTROL); N is the absolute value of the key depressed (key minus SHIFT and/or CONTROL); SHIF is the offset for unshifted, shifted, control, or shift-control character groups (0 = unshifted, 64 = shifted, 128 = control, and 192 = shift-control); VERS is the high-bit condition for inverse mode (regular = 0, inverse = 128); and MV is the flag for whether movement is to take place upon leaving the subroutine (1= movement).

220. Get the key pressed from the Keycode Subroutine at 785; if the key is an arrow key, jump to the arrow key routine at 250; if it is SHIFT-DELETE, jump to the Delete Line Subroutine at 60; if it is SHIFT-INSERT, jump to the Insert Line Subroutine at 90.

225. If the key was CONTROL-ESC, toggle the auto-advance flag AV from 0 to 1 or back again.

230. If the key was CAPS-LOWR, set SHIF to the appropriate value. CAPS-LOWR alone = 0, SHIFT-CAPS-LOWR = 64, CONTROL-CAPS-LOWR=128, and SHIFT-CONTROL-CAPSLOWR=192. Jump to the subroutine at 930, which changes the keyboard display on the bottom four lines of the screen to show the current character group.

235. If the key was the Atari logo key (or inverse key), toggle the value of VERS from 0 to 128 or back again.

240-245. If none of the above commands was executed, change OLD to the internal character code of the character called for, using the array C(n), and POKE that value into the current cursor position (SC + PIX). If AV is set to 1, change the value of C to 135 (right arrow).

250. Set the value of V and H as required by the arrow key pressed, and set the flag MV to 1 to indicate that a move is called for.

220 GOSUB 785:
    ON (C=134)+(C=135)+(C=142)+(C=143)+2*(C=116)+3*(C=119)+4*(C-246)
       GOTO 250,60,90,645 
225 IF C=156 THEN AV=1*(AV=0):GOTO 920
230 IF N=60 THEN SHIF=4+C-64: POKE 53279,4:GOSUB 930:RETURN 
235 IF N=39 THEN VERS=128*(VERS=0):GOTO 920 
240 OLD=C(N+SHIF)+VERS:POKE SC+PIX,OLD:ON AV GOTO 245: RETURN 
245 C=135 
250 V=WIDE*((C=143)-(C=142)):H=(C=135)-(C=134):MV=1:RETURN

Color Change Subroutine. DI is the joystick position, T is the joystick trigger (0 = pressed, 1 = not pressed), OPT is the console key, and COL1-COL5 are the addresses of the color registers.

255-260. The exit and entrance routines. 920 is the Delay Subroutine. The exit routine also POKEs the cursor character into place and RETURNs.

265-275. Read the joystick, button, and console keys. If START is pressed, exit the routine through 255. The four legal directions are 7, 11, 13, and 14. Change a 7 to a 12, then subtract 10; now if the joystick is indicating a legal direction, the value of DI will be 1, 2, 3, or 4. If it isn't one of those, go back and read again. If it is, use those plus T to get to the right line.

280-315. Read the color register and change the value as appropriate. Lines 310 and 320 change the inverse color register (COL4) if SELECT was pressed; otherwise, line 315 or 325 is executed.

255 GOSUB 920:POKE SC+PIX,91:RETURN 
260 GOSUB 920 
265 DI=PEEK(632):T=PEEK(644):DI=DI+5*(DI=7):
    DI=DI-10:OPT=PEEK(53279):IV=(OPT=5):IF OPT=6 THEN 255 
270 IF DI<1 OR DI>4 THEN 265 
275 ON (4*T)+DI GOSUB 280,285,290,295,300,305,310,320:GOTO 265 
280 POKE COL5,PEEK(COL5)-2+256*(PEEK(COL5)<2):RETURN 
285 POKE COL5,PEEK(COL5)+2-256*(PEEK(COL5)>253):RETURN 
290 POKE COL3,PEEK(COL3)-2+256*(PEEK(COL3)<2): RETURN 
295 POKE COL3,PEEK(COL3)+2-256*(PEEK(COL3)>253):RETURN 
300 POKE COL2,PEEK(COL2)-2+256*(PEEK(COL2)<2):RETURN 
305 POKE COL2,PEEK(COL2)+2-256*(PEEK(COL2)>253):RETURN
310 IF IV THEN POKE COL4,PEEK(COL4)-2+256*(PEEK(COL4)<2):RETURN
315 POKE COL1,PEEK(COL1)-2+256*(PEEK(COL1)<2):RETURN
320 IF IV THEN POKE COL4,PEEK(COL4)+2-256*(PEEK(COL4)>253):RETURN
325 POKE COL1,PEEK(COL1)+2-256*(PEEK(COL1)>253):RETURN

Filename Test Subroutine. This routine takes apart the filename that the user entered; removes anything before a colon, anything after a period, and any letters beyond the first eight; and provides error messages if there is nothing left, or if the name doesn't begin with a capital letter, or if there are illegal characters in the filename. If the name failed, flag N is set to 1.

330 FLL$=FL$:FOR I=1 TO LEN(FL$):N=ASC(FL$(I,I)):
    ON N=58 GOSUB 370:NEXT I:FL$=FLL$
335 FLL$=FL$:FOR I=1 TO LEN(FL$):N=ASC(FL$(I,I)):
    ON N=46 GOSUB 375:NEXT I:FL$=FLL$
340 IF LEN(FL$)>8 THEN FL$=FL$(1,8)
345 IF LEN(FL$)<1 THEN 390
350 N=ASC(FL$(1,1)):IF N>90 OR N<65 THEN 385
355 IF LEN(FL$)<2 THEN GOTO 365
360 FOR I=2 TO LEN(FL$):N=ASC(FL$(I, I)):ON (N>90 OR N<65) AND (N>57
OR N<48) GOTO 380:NEXT I
365 FLL$="D1:":FLL$(4)=FL$:N=0:RETURN
370 FLL$=FL$(I+1,LEN(FL$)):RETURN
375 FLL$=FL$(1,I-1):RETURN
380 POP :? " {CLEAR}":? "Illegal characters in ";FL$:GOTO 390
385 ? "{CLEAR}":? FL$;" must start with a capital":? "letter.":GOTO 390
390 ? "Let's try that name again.":N=1:RETURN

Disk Test Subroutines. These routines test to see if a file is present on the disk. If not, flag N is set to 1.

395-410. Check to see if file FL$ is on the disk. If it isn't,warn the user.

415-435. Check to see if file FL$ is on the disk. If it is,warn the user.

395 TRAP 400: OPEN #1,4,0,FL$:N=0:CLOSE #1:RETURN
400 ? :? FL$;" isn't on disk in":? "drive 1":
    ? "Insert disk with ";FL$;"and":? "press RETURN.":CLOSE #1
405 ? "Or to try another file name, press any other key."
410 ON PEEK(753)<>3 GOTO 410:GOSUB 785:ON N=12 GOTO 395:N=1:RETURN
415 TRAP 435: OPEN #1,4,0,FL$:? FL$;" is already on disk.":
    ? "Unless you change the name, the old"
420 ? "file will be lost. To change the name press RETURN":
    ? "Or press any other key to continue.":CLOSE #1
425 ON PEEK(753)<>3 GOTO 425: GOSUB 785:ON N=12 GOTO 430:N=0:RETURN
430 N=1:RETURN
435 CLOSE #1:N=0:RETURN

Setup Routine. This long routine sets up the parameters for editing or creating the display.

440. Print the program name and run the Keycode Array Subroutine at 905.

445-460. Get a character set directory through the Directory Subroutine at 850, then get the user's choice of character set and test it through the Filename Test Subroutine at 330 and the Disk Test Subroutine at 395.

465-475. Get a screen file directory through the Directory Subroutine at 840, then get the user's save filename (FSAVE$) and test it at 330 and 415.

480-485. Find out if the user wants to edit a previously saved file. If not, skip on to 535.

490-530. Get the user's load filename and test it at 330 and 395. If the filename fails, go back to 480 so the user has the option of not loading a file after all. If the filename succeeds, then get the mode (MD), width (WD), and length (LN) parameters from the load file. Ask if the user wants to change the parameters. If not, jump to 585 for the final check; if yes, then proceed to 540.

535. Set the flag FLOAD to 0, which means there is no load file.

540-550. Get the user's choice of mode. Only 2, 4 and 5 are acceptable.

555-560. Get the user's choice of line width (WIDE). The minimum is 40 characters per line; the subroutine at 790 determines the maximum.

565-580. Get the user's choice of number of lines in the display (LINE). Minimum and maximum depend on mode and line width. The display cannot be longer than 4K.

585-600. Show the user what the parameters are and get the user's decision about whether to proceed or not. If not, go back to 440.

440 ? "{13 SPACES}Fontbyter":? :? :? :GOSUB 905
445 G0SUB 850:? "What is the name of your character{4 SPACES}
    set? (Enter '@' for ROM set)":POKE 764,255:INPUT F$
450 IF F$="@" THEN 465
455 FL$=F$:GOSUB 330:ON N GOTO 445:F$=FLL$:F$(LEN(FLL$)+1)=".SET"
460 FL$=F$:GOSUB 395:ON N GOTO 445
465 GOSUB 840:? :? "What file should hold your finished{3 SPACES}
    screen? (Eight characters)":POKE 764,255:INPUT FSAVE$
470 FL$=FSAVE$:GOSUB 330:ON N GOTO 465:FSAVE$=FLL$:
    FSAVE$(LEN(FLL$)+1)=".SCR"
475 FL$=FSAVE$:GOSUB 415:ON N GOTO 465
480 FLOAD$="":? :? "Would you like to edit a screen you{3 SPACES}
    have already saved? (Y or N) "
485 GOSUB 785:ON N=35 GOTO 535:ON N=43 GOTO 490:GOTO 485
490 ? :? "What is the name of the saved  screen file? ":
    POKE 764,255:INPUT FLOAD$
495 FL$=FLOAD$:GOSUB 330:ON N=0 GOTO 500:GOTO 480
500 FLOAD$=FLL$:FLOAD$(LEN(FLL$)+1)=".SCR"
505 FL$=FLOAD$:GOSUB 395:ON N GOTO 480:OPEN #1,4,0,FLOAD$:
    GET #1,MD:GET #1,WD:GET #1,LN:CLOSE #1:FLOAD=1
510 IF MD>5 THEN MD=MD-10:WD=WD+256
515 ? :? FLOAD$;" was saved as:":? "Mode ";MD;",":
    ? "with ";LN;" lines":? "of ";WD;" characters per line."
520 ? "If you wish to change these parameters press RETURN.":
    ? "To leave them unchanged press any {5 SPACES}other key."
525 ON PEEK(753)<>3 GOTO 525:GOSUB 785:IF N=12 THEN 540
530 MODE=MD:WIDE=WD:LINE=LN:GOTO 585
535 FLOAD=0
540 ? :? "What Antic mode will you work in?":
    ? "(Antic 2, 4, OR 5) ":POKE 764,255
545 GOSUB 785:ON N<>30 AND N<>24 AND N<>29 GOTO 545
550 MODE=C(N)-16
555 ? :? "How wide a line?":? " (Minimum 40 characters":
    ? "{3 SPACES}maximum ";170+170*(MODE=5);" characters)"
560 POKE 764,255:TRAP 560:INPUT WIDE:WIDE=INT(WIDE):
    ON WIDE<40 OR WIDE>170 GOSUB 790
565 ? :? "How many lines do you want to edit?{5 SPACES}
    (Minimum ";12+12*(MODE<>5);:? "{3 SPACES}Maximum ";INT(4096/WIDE);")"
570 TRAP 570:INPUT LINE
575 LINE=INT(LINE):IF LINE>INT(4096/WIDE) THEN LINE=INT(4096/WIDE)
580 IF LINE<12+12*(MODE=4) THEN LINE=12+12*(MODE=4)
585 ? "{CLEAR}":? "You have chosen:":? "Character set--";F$:
    ? "Save File--";FSAVE$:? "Load file--";FLOAD$
590 SZ=LINE*WIDE-1:? "Mode ";MODE:? LINE;" lines of ";WIDE;" characters"
595 ? "If this is right, press START{9 SPACES}
    To make changes, press OPTION"
600 ON (PEEK(53279)=6)+(2*(PEEK(53279)=3)) GOTO 605,440:GOTO 600

Initialization. A is the old top of memory; TOP is the new top of memory; CHBAS is the page number of the character set; CH is the absolute address of the character set; SP is the page number of the start of screen memory; SC is the absolute address of the start of screen memory; and OLDCHBAS is the ROM character set page number. (ICCOM, ICBADR, and ICBLEN are explained in the notes for lines 20-35.)

605. Move memory down by 24 pages (6K) to reserve space for screen memory, the character set, the display list, and other protected data. Set addresses.

610-615. Print the wait message. If the user specified the ROM character set ("@"), skip to 630.

620-625. Use a machine language routine to read the character set from disk and load it at CH.

630. Turn off the screen, run the setup subroutines, and jump to the main loop at 120.

605 A=PEEK(106):TOP=A-24:CHBAS=TOP:CH=CHBAS*256:SP=TOP+8:
    SC=SP*256:POKE 106,TOP:OLDCHBAS=224:GRAPHICS 0 
610 ? "Just a minute while I get myself{6 SPACES}together . . ."
615 IF F$="@" THEN CHBAS=224:CH=CHBAS*256:GOTO 630
620 OPEN #1,4,0,F$:POKE ICBADR+X+1,CHBAS:POKE ICBADR+X,0:
    POKE ICBLEN+X+1,4:POKE ICBLEN+X,0 
625 POKE ICCOH+X,7:
    C=USR(ADR("hhh{inverse asterisk}LV{inverse small d}"),X):CLOSE #1
630 POKE 559, 0:GOSUB 640:GOSUB 655:GOSUB 810:GOSUB 635:
    ON FLOAD GOSUB 650:GOSUB 925:GOTO 120

Set CHBAS Subroutine. Tell the operating system where the character set is.

635 POKE 756,CHBAS:RETURN

Clear Memory Subroutine. Machine language routine to M screen memory with zeros. (Anything in brackets should be entered with the CONTROL key depressed.)

640 OPEN #1,4,0,"D1:CLEAR.SUB":FOR I=1 TO 33: GET #1,N:
    CLEAR$(I,I)=CHR$(N):NEXT I: CLOSE #1
645 C=USR(ADR(CLEAR$),SP,X):RETURN 

Load FLOAD$ Subroutine. Set FL$ TO FLOAD$ and run the Display Load Subroutine at 20.

650 T=SZ:FL$=FLOAD$:GOSUB 20:SZ=T:RETURN

Display List Subroutine. DL is the address of the display list; DL4 + 256*DL5 is the address of the first screen memory address instruction in the display list; MENU is the address of the keyboard layout display; DLMEN is the display list instruction giving the low byte of the address of the keyboard layout display; DISPLAY is the address of the machine language scroll subroutine; WHI is the high byte of WIDE; WLO is the low byte of WIDE.

655-665. Set up the display list for screen memory.

670-675. Set up the display list for the keyboard layout display window.

680-700. End the display list; load the scrolling subroutine from disk to DISPLAY; set up the parameters DISPLAY will use (WHI and WLO); and POKE the address of the display list into locations 560 and 561.

655 DL=2568(TOP+4):DL4=DL+4:DL5=DL+5:FOR I=0 TO 2:
    POKE DL+I,112:NEXT I:PIX=0:N=0
660 FOR I=DL+3 TO DL+27+36*(MODE<>5) STEP 3:C=SC+N*WIDE:
    POKE I,64+MODE:POKE I+2,INT(C/256)
665 POKE I+1,C-256*PEEK(I+2):N=N+1:NEXT I
670 N=0:MENU=256*(TOP+5)+64:DLMEN=DL+32+36*(MODE<>5):
    POKE DLMEN-2,MODE+64:POKE DLMEN,INT(MENU/256)
675 POKE DLMEN-1,MENU-256*PEEK(DLMEN):FOR I=DLMEN+1 TO DLMEN+3:
    POKE I,MODE:NEXT I
680 POKE I,65:POKE I+1,0:POKE I+2,DL/256:OPEN #1,4,0,"D:DISPLAY.SUB" 
685 DISPLAY=DL+128:TRAP 690:FOR I=0 TO 186:GET #1,N:
    POKE DISPLAY+I,N:NEXT I:GOTO 695
690 POP
695 WHI=INT(WIDE/256):WLO=WIDE-256*WHI:POKE DL+112,WLO:
    POKE DL+113,WHI
700 POKE 560,0:POKE 561,DL/256:CLOSE #1:RETURN

Stop Edit Subroutine. This routine begins by executing the Display Save Subroutine at 20, restoring the ROM character set, and changing to GRAPHICS 0. Then the user decides whether to change the name of "D1:TEMPFILE.SCR" to FSAVE$, whether to quit or not, and whether to return to edit the same screen or start Fontbyter over.

705-740. Save the screen and get the user's choices.

745. Restore the old top of memory and start the program over.

750-755. Return to edit the same screen. The flag FSAVE tells whether the screen is on disk as "D1:TEMPFILE.SCR" or FSAVE$.

760. Restore the top of memory, clear the keyboard buffer, and quit.

765-780. Check to see if a file named FSAVE$ is already on the disk. If it is, unlock it and erase it. Then change the name of "D1:TEMPFILE.SCR" to FSAVE$.

705 POKE SC+PIX,OLD:G0SUB 40:POKE 756,OLDCHBAS:
    GRAPHICS 0:POKE 764,255
710 ? "Screen is saved as D1:TEMPFILE.SCR":? :
    ? "Do you want to save the screen as":
    ? FSAVE$;"? (Y or N)"
715 G0SUB 785:ON N<>43 AND N<>35 G0TO 715:IF N=43 THEN G0SUB 765:G0TO 725
720 FSAVE=0
725 ? :? "Do you want to quit? (Y or N)":POKE 764,255
730 G0SUB 785:ON N<>43 AND N<>35 GOTO 730:ON N=35 G0TO 735:
    ON N=43 GOTO 760
735 ? :? "To return to edit the same screen,{4 SPACES}press OPTION":? :
    ? "To start FONTBYTER over, press START"
740 OPT=PEEK(53279):ON ((OPT=6)+(2*(OPT=3))) G0TO 745,750:G0TO 740
745 POKE 106,A:GRAPHICS 0:GOTO 10
750 POKE 106,TOP:G0SUB 635:FL$="D1:TEMPFILE.SCR":IF FSAVE=1 THEN FL$=FSAVE$
755 G0SUB 20:G0SUB 655:G0TO 120
760 POKE 106,A:POKE 764, 255:GRAPHICS 0:END
765 FSAVE=1:TRAP 770:OPEN #2,4,0,FSAVE$:CLOSE #2:XIO 36,#2,0,0,FSAVE$:
    XIO 33,#2,0,0,FSAVE$:G0TO 775
770 CLOSE #2
775 FL$="D1:TEMPFILE.SCR,":FLL$=FSAVE$(4,LEN(FSAVE$)):FL$(17)=FLL$
780 XIO 32,#1,0,0,FL$:RETURN

Keycode Subroutine. Read the keyboard buffer at 764. C is the actual key combination, and N is the key pressed, regardless of the CONTROL and SHIFT keys.

785 C=PEEK(764):N=C-64*INT(C/64):RETURN

Test WIDE Subroutine. Check to make sure WIDE is within the legal range.

790 IF WIDE<40 THEN WIDE=40:RETURN
795 IF WIDE>170 AND MODE<>5 THEN WIDE=170:RETURN
800 IF WIDE<340 THEN RETURN
805 WIDE=340: RETURN

Load DELETE$ and EXPAND$. Read these two machine language subroutines from disk files "D1:DELETE.SUB" and "D1:EXPAND.SUB", and store them as strings DELETE$ and EXPAND$.

810 TRAP 815:OPEN #1,4,0,"D:DELETE.SUB":FOR I=1 TO 124:
    GET #1,N:DELETE$(I,I)=CHR*(N):NEXT I:GOTO 820
815 POP
820 CLOSE #1:WHI=INT(WIDE/256):WLO=WIDE-256*WHI
825 TRAP 830:OPEN #1,4,0,"D:EXPAND.SUB":FOR I=1 TO 124:GET #1,N:
    EXPAND$(I,I)=CHR$(N):NEXT I:GOTO 835
830 POP
835 CLOSE #I: RETURN

Get Directory Subroutine. Get a directory of disk files with a particular extender and display it. Entry point 840 gets a directory of SCReen files, and entry point 850 gets a directory of character SETs.

840 TRAP 865:XIO 36,#1,0,0,"D:*.SCR" 
845 ? :? "Currently saved screen files:":FLL$="SCR":GOTO 860
850 TRAP 865:XIO 35,#1,0,0,"D:*.SET" 
855 ? :? "Currently available character sets:":FLL$="SET"
860 FL$="D1:*.":FL$(LEN(FL$)+1)=FLL$:OPEN #1,6,0,FL$:FOR I=0 TO 50:
    INPUT #1,FLL$:? FLL$:NEXT I
865 CLOSE #I:RETURN

Quick Scroll Subroutine. This routine eliminates the cursor and reads the joystick to determine the direction of the scroll. It does not change screen memory, only the area of screen memory being read by the display list. Pressing START ends this routine.

870 GOSUB 920:POKE SC+PIX,OLD:GOTO 895
875 WV=2*((DI=5)+(DI=13)+(DI=9))+(DI=10)+(DI=6)+(DI=14):
    WH=2*(DI<8 AND DI>4)+(DI<12 AND DI>8)
880 W=(PEEK(DL4)+256*PEEK(DL5))-SC:U=INT(W/WIDE):
    WV=WV-(U=0 AND WV=1)-2*((U+7+12*(MODE<>5)=LINE-2) AND WV=2)
885 L=W-(U*WIDE):WH=WH-(L=0 AND WH=1)-2*((L+40)=WIDE AND WH=2)
890 POKE DL+114,WH: POKE DL+115,WV:C=USR(DISPLAY)
895 IF PEEK(53279)<>6 THEN DI=PEEK(632):ON DI<>15 GOTO 875:GOTO 895
900 PIX=PEEK(DL4)+256*PEEK(DL5)+(6+6*(MODE<>5))*WIDE+20:
    OLD=PEEK(PIX):PIX=PIX-SC:RETURN

Keycode Array Subroutine. This routine creates an array C(n) such that in each array element C(X), X is the keyboard code read from 764 and C(X) is the internal character code value for the key depressed. The values are read from the disk file "D1:CHARDATA.DAT"

905 OPEN #4,4,0,"D:CHARDATA.DAT"
910 FOR I=0 TO 255:GET #4,N:C(I)=N:NEXT I
915 CLOSE #4: RETURN

Delay Subroutine. This routine sounds the console buzzer and takes up time, so that users have time to lift their fingers from the keyboard to avoid repeating a command.

920 FOR I=0 TO 10:POKE 53279,4:NEXT I:RETURN

Load Keyboard Display. This routine sets up the keyboard display on the bottom four lines of the screen. If the routine is entered at line 930, it causes the currently available character group (MENSH) to be displayed.

925 OPEN #1,4,0,"D:MENU.DAT":FOR I=4 TO 483:GET #1,N:
    POKE MENU+I,N:NEXT I:CLOSE #1
930 MENSH=MENU+160*INT(SHIF/64):POKE DLMEN,INT(MENSH/256):
    POKE DLMEN-1,MENSH-256*PEEK(DLMEN):RETURN


Compile Fontbyter

Fontbyter will run much more quickly if the BASIC program is compiled. Program 8 is listed here for those users who wish to make a compiled version. If the lines from Program 8 are added to or substituted for lines in Fontbyter, the program will compile using Monarch Data Systems' ABC Compiler.


Program 2. Machine Language Scrolling Subroutine

Download P151L2.BAS (Saved BASIC)
Download / View P151L2.LST (Listed BASIC)

Program 3. Machine Language Line Insert Subroutine

Download P152L3.BAS (Saved BASIC)
Download / View P152L3.LST (Listed BASIC)

Program 4. Machine Language Line Delete Subroutine

Download P152L4.BAS (Saved BASIC)
Download / View P152L4.LST (Listed BASIC)

Program 5. Data for Keyboard Display

Download P153L5.BAS (Saved BASIC)
Download / View P153L5.LST (Listed BASIC)

Program 6. Data for Keycode Array

Download P155L6.BAS (Saved BASIC)
Download / View P155L6.LST (Listed BASIC)

Program 7. Clear Subroutines

Download P155L7.BAS (Saved BASIC)
Download / View P155L7.LST (Listed BASIC)

Program 8. Altered Lines for Compiler Version

Download P156L8.BAS (Saved BASIC)
Download / View P156L8.LST (Listed BASIC)

Return to Table of Contents | Previous Section | Next Section