GFA BASIC Class 1 BASIC What is it? BASIC stands for Beginners All purpose Symbolic Instruction Code. BASIC consists of commands (specific words) that when entered through a BASIC interpreter form a 'Statement'. A statement is simply an instruction to the computer to perform a specific task. All computers understand only 1 language directly, called machine language. Machine language consists of series of numbers (1's and 0's). Assembly language is sometimes referred to as machine language. Any programming language other than Assembly or machine language is known as an interpreted language, in other words, the computer translates the commands you enter into machine language which it can understand. This translation is what sometimes causes other languages to be slower than Assembly language. Why learn another language then? Why not learn Assembly and save the time of this translation? Simple, Assembly or machine language is cryptic! The commands are not easily understood and every different computer chip uses a different set of instructions. Assembly is by far the fastest and most efficient language, also the hardest to learn (in my opinion anyway). BASIC on any computer uses an interpreter for you to enter your code. The interpreter then translates those commands into machine language. The relative ease of learning and using BASIC is why we're here. Lets proceed... Through the course of this instruction the only thing that's required is GFA Basic itself. After you learn to write your own programs you may want to consider purchasing the GFA Compiler. It allows you to convert your basic programs into regular .PRG files that you can run from the desktop without having to load GFA Basic first. Also, the GFA Companion is helpful in constructing GEM menus, alert boxes, text boxes and 'pop-up' menus. The companion also includes a very good disk tutorial for GFA beginners. Items I strongly urge you to get immediately are: DIOX95.ARC - A shareware program that constructs dialog boxes for you and actually writes the GFA source code to merge into your own programs. GFATIPS.ARC - A series of GFA tutorials with example programs included written by John Holder (author of GFA Companion) Misc GFA programs - you can print them out and use them to study other programmers techniques. The 3 items mentioned above are available on the STarBase BBS (904- 581-2866, 1200/2400 baud, 24 hours daily) if you have a modem or from the STar library if you contact Hobart Neighbors. All the files include documentation which I suggest you print out as much as possible as it makes a good source for future reference. Several of the ST magazines have ongoing articles pertaining to GFA Basic, some very good. Other suggested reading sources are: GFA Basic Training - Reboot Camp - An excellent tutorial written specifically for the GFA novice. This will teach you a lot of the basics if you're a true beginning programmer. GFA Basic Book - Written by the author of GFA Basic himself. This book is for intermediate to advanced level programmers. A lot of good info here although it gets quite complex at times. Save this for when you've truly mastered the main commands and functions of the language. GFA Basic Quick Reference Guide by Abacus - Another reference type of book that includes additional examples of some of the commands. Very similar to the GFA book that comes with the language. On to the good stuff... (***NOTE*** the familiarization with the editor and keyboard commands referenced here were covered in our User Group lessons, if you're reading this from the tutorial, please study your GFA Owners Manual and learn to use the editor, it works!) Initially we'll cover familiarization with the editor in GFA. You'll learn how to use both the mouse and the keyboard to perform all the needed functions. We'll then progress to some of the most basic commands (and the most frequently used commands) to thoroughly familiarize you with them. Three different filename extensions will be used, .BAS (or .GFA),.BAK and .LST. The .BAS extender indicates that the program is a basic program that requires the GFA Basic interpreter (or the Run Only version) to run the program. Almost all the Basic interpreters use the .BAS extension so to identify the GFA only programs, some programmers began using .GFA as an extension to differentiate between the different interpreters. You CAN modify your GFA Basic program to list and load programs with a .GFA extension instead of the .BAS extension however, this should be left to those with some experience modifying programs in this fashion. The second time you save a file, GFA automatically renames any previous version of your program to .BAK to provide you with a backup. The .LST extension indicates a GFA program saved in ASCII format. To load these type of programs, you need to use the Merge feature within the interpreter. The advantage to saving your files in ASCII format is that they can be viewed/printed from the desktop. The disadvantage is that they take longer to save/load. Subroutines that you intend to use in different programs should be saved in this format as they can then be merged into any of your programs. One thing to remember when using GFA is that you may only enter 1 command per line. This tends to make your listings (programs) a little longer but this is also where GFA gains a lot of its speed. The interpreter will check each line you enter after you press . If there's an error, it will tell you. You may enter your commands in either upper or lowercase letters and GFA will automatically correct them for you. For ease of illustration, I'll show all GFA commands in uppercase letters. Some of the commands we'll learn to use during this first lesson will include: PRINT (or ?) - simply tells the computer to print a statement on the screen. EXAMPLE: PRINT "Hello there!" - notice the text we want printed is enclosed in quotation marks. The computer will print anything between the quotation marks up to a maximum of 255 characters. Instead of typing PRINT you may use the question mark and GFA will change it for you to PRINT. This is simply a shortcut. EXAMPLE: ? "Hello there!" - notice you still need the quote marks. PRINT AT(X,Y) - tells GFA to print a statement at a specific location with 'X' being the column and 'Y' being the row. EXAMPLE: PRINT AT(10,10);"Hello there!" - the quotes are still there and the only difference is this statement will print Hello there! beginning at the 10th column and the 10th row. REM (or ' or !) - tells GFA to ignore the statement that follows as it is only a comment for your use. Uses would be to insert comments in your program such as REM This changes colors. If you ever need to find where you change the colors in your program, it's easier to look for the comment you left yourself explaining what you did. REM or ' may be used at the beginning of a line only and indicates that GFA should ignore the entire line. The ' symbol is a shortcut. When you want to enter a comment on the same line as your statement, use the ! character. The ! tells GFA that the text following it is simply a comment for your use. EXAMPLE (EX1): REM Program to print Hello there! (GFA ignores this) ' By Tom Hayslett (GFA ignores this line also) PRINT "Hello there!" !Actual program PAUSE X - Tells GFA to wait a specified period of time before continuing. 'X' can be any whole number. 50=1 second so if your command is PAUSE 100, you're telling GFA to wait 2 seconds and then continue. EXAMPLE (EX2): REM Program to pause PAUSE 50 !Waits 1 second PAUSE 300 !Waits 6 seconds CLS - Tells GFA to clear the screen. This will help keep your program looking more professional and it's very fast. It doesn't need anything else used with it to work. EXAMPLE: CLS KEY=INP(2) - This statement tells GFA to wait for the user to press any key. This can be very useful when you want to display information to whomever is using your program and you want your program to continue after they've read the information and pressed any key. EXAMPLE: KEY=INP(2) The 2 in parentheses indicates we're waiting for any input from the keyboard. GFA uses this command to wait for input from other sources also but we'll save them for another lesson. EDIT - Tells GFA to return you to the editor. Again, no additional commands are needed. Now, lets use what we've learned to write a short and simple program. See if you can follow exactly what we're doing in the following program (EX3). REM Our first program in GFA PRINT AT(35,11);"Hello there!" !Prints at column 35, row 11 PRINT AT(30,22);"Press any key to continue..." KEY=INP(2) !Wait for a key to be pressed CLS !Clears the screen PRINT AT(35,11);"Thank you!" PAUSE 250 !Pauses for 5 seconds CLS PRINT "Returning to the editor..." PAUSE 150 EDIT !Returns us to the GFA editor That's it for the introduction and some of the simpler yet most commonly used commands. Hopefully I'll be able to keep writing these files to help you beginners progress. Don't forget though that after you do become somewhat proficient at the language yourself, I expect to learn some tricks from you! Class 2 I'm not going to review what we learned last time since you have the documentation from class 1. We do however, need to go into a little explanation here first... When working in the editor, the 'NEW' command will erase the current program you have in memory and allow you to start again with a fresh editor. Care should be exercised when entering the NEW command, be sure you've saved any program you want to keep BEFORE entering NEW. Variables are used extensively in any BASIC language we use. A variable is simply a symbol (usually a letter or word or number) that we use in a program when that variable needs to change to many different values (or characters). For example, I know you've all seen or heard statements like this one pertaining to programming 'LET X=5' (for some reason, 'X' seems to be popular). All this means is that we've assigned the value of 5 to a variable called 'X'. If we had a short program like this (EX21): LET X=5 PRINT X Guess what would be printed? Right, the number 5. Okay, there are several different types of variables we may use to help BASIC understand what type of information we want it to save. All variables MUST start with a letter and be ONLY 1 word long. You should NOT use a BASIC command as a variable (even though it IS possible). Another example (EX22): LET Our_number=5 PRINT Our_number This statement is functionally identical to the first example. Notice that when I used the variable 'Our_number', there's an underscore connecting the 2 words. This is to keep our variable 1 'word' long (remember the rules?). Now for some of the different TYPES of variables we may use. A letter or word alone indicates 'normal' or 'real' variables. They can be numbers only and are accurate to 11 digits. EXAMPLE: LET X=234.15723 assigns that numeric value to the variable 'X'. A variable with a suffix of '%' indicates an 'integer' variable, in other words, whole numbers between 2, 147,483,647 and -2,147,483,648. The advantage of 'integer' variables is that they are much faster as BASIC doesn't have to compute the numbers out to 11 places (including decimal places). EXAMPLE: LET X%=5 assigns the number 5 to our 'integer' variable 'X%'. Another type of variable is the 'string' variable. These are indicated by the suffix '$' and can contain ANY characters less than 255 in length. The value assigned to string variables must be enclosed in quotation marks. EXAMPLE: LET X$="Hello there!". This assigns the 'value' 'Hello there!' to the string variable 'X$'. You may change the value of a variable within a program by assigning it a new value and the use of 'LET' is optional. EXAMPLE (EX23): REM Short variable routine LET X=1 !I could have left 'LET' out Y=2 !I DID leave 'LET' out Total%=3 !Notice the '%'? 'Total%' is only another variable NAM$="Tom Hayslett" !You may have spaces or ANYTHING in there LONG_NAM$="Thomas W. Hayslett, W?" !Any characters (up to 255) ' !A 'REM' line to separate parts of our program PRINT X PRINT Y PRINT Total% PRINT NAM$ ? LONG_NAM$ Our screen would look like this: 1 2 3 Tom Hayslett (Notice it does NOT print the quotes!) Thomas W. Hayslett, W? Simple huh? Now lets see how we can use variables for a good purpose. You may perform mathematical functions on numeric variables just as if they were numbers. Math functions in BASIC include '+' or 'ADD' for addition, '-' or 'SUB' for subtraction, '/' or 'DIV' for division and '*' or 'MUL' for multiplication. There are also '=' for equal to, '<>' for not equal to, '<' for less than, '>' for greater than, '<= or =<' for equal to or less than and '>= or =>' for equal to or greater than. EXAMPLE (EX24): X%=10 Y%=5 Total%=X%+Y% ? Total% This would print the integer variable 'Total%' on our screen which has the value of 'X%' and 'Y%' added together. It would print 15. You may also use some of the mathematical symbols to combine string variables. EXAMPLE (EX25): NAM$="Tom" Last_nam$="Hayslett" ? NAM$+Last_nam$ You must enclose your string variables in quotes and guess what our example would print? It would print TomHayslett. Oops! To correct this, we would have to change our string variable 'NAM$' to "Tom ", the space would also print making our screen show Tom Hayslett. Now, to make what we've learned useful, our numbers and strings must come from somewhere so where do we get them? One common source is from the person using our program. How? We use the 'INPUT' command. It's use is simple, EXAMPLE: INPUT X%. This pauses and waits for the user to enter a number. If they enter a character (A,b,q,etc.), a bell will sound and they can try again. The 'INPUT' command will also print a question mark for you if you use a semicolon with it like this: INPUT;X% You may also include instructions with the input command if you use it like this: INPUT "Instructions";X% 'Instructions' may be any string of text you want to precede the question mark. You may also request input of a character string by simply requesting a string variable. EXAMPLE: INPUT "Please enter your name";NAM$ Our screen would look like this: Please enter your name? _ (The underscore indicates where our flashing cursor would be) Okay, now on to another example (EX26). REM Example program using input, variables and math CLS !Clear the screen ? !Print a blank line INPUT "Please enter your name and press RETURN ",NAM$ !See below ' This asks the user to enter their name ? Print another blank line INPUT "Now, please enter a number ",X% ? INPUT "A second number also please ",Y% ? ? "Thank you "NAM$", please touch any key and I'll print the" ? "total of the 2 numbers you entered..." Key=INP(2) !Wait for any key to be pressed Total%=X%+Y% PRINT AT(39,12);Total% !Prints total of the 2 numbers PAUSE 150 !Pause for 3 seconds CLS PRINT AT(36,12);"Goodbye "NAM$", returning to the editor" PAUSE 200 EDIT Whew! If you follow the program line by line it's easy to see exactly what it's doing in each step. You may also combine your INPUT statements and ask for more than one item at a time as follows, INPUT "Name and age: ",NAM$,AGE%. Notice we used a comma instead of a semi colon (same as in the first few lines of the example program above)? The comma along with the semicolon allows us to define how we want the screen to look when we request information. We could also use it like this: INPUT "Name and age? ",NAM$,AGE%. We may include the ? if we desire. We need to learn a few other commands now to make what we've already learned more meaningful. We're going to learn about several types of loops. A loop is simply a routine in a program that continues whatever process it's doing until a pre determined condition is met. Lets start with the simplest form first, the IF THEN type of loop. An 'IF...THEN' really isn't a true loop per say but it's often used as one. IF sets up a condition that if true will process a certain statement. Every IF must be ended with an 'ENDIF'. A simple form is as follows (EX27): IF NAM$="Tom" THEN PRINT "Hello Tom" ENDIF If the condition is true (string variable 'NAM$' = Tom), the following command is executed. If our string variable 'NAM$' does NOT = Tom, the complete loop would be bypassed. What if we wanted it to do something else if that condition wasn't met? Here's where the 'ELSE' command comes into play. It means if the preceding statement wasn't true then do this. For example (EX28): IF NAM$="Tom" THEN PRINT "Hello Tom" ELSE PRINT "Hello somebody else" ENDIF In this case, if our string variable = Tom it would print 'Hello Tom', if it didn't equal 'Tom' it would print 'Hello somebody else" then it would end the 'if' (leave the loop). These 'IF...THEN...ELSE...ENDIF' commands can be nested, that is you may have them inside another 'IF...ENDIF' loop. The editor in GFA will help you keep track of how many loops you are deep as it controls the indenting of the commands. Each 'IF' must be closed with an 'ENDIF'. Another example (EX29): IF NAM$="Tom" THEN PRINT "Hello Tom" ELSE IF NAM$="Bob" THEN PRINT "Hello Bob" ENDIF ENDIF Notice we have 2 'ENDIF' commands because we have 2 'IF's. A numeric example would be as follows (EX210): INPUT "Please enter a number between 1 and 10",NUM% IF NUM%< 5 THEN PRINT "Your number is less than 5" ELSE IF NUM%=>5 AND NUM%<=10 THEN PRINT "Your number is larger than 4 but less than 11" ELSE PRINT "You cheated! Your number was too big!" ENDIF ENDIF This asks for a number to be entered that's between 1 and 10 (NUM%). If the number is less than 5 it prints 'Your number was less than 5'. If the number is equal to or greater than 5 AND equal to or less than 10 it prints 'Your number is larger than 4 but less than 11'. If the user enters a number larger than 10, it goes to the 'ELSE' which prints 'You cheated! Your number was too big!'. Then we have our 2 'ENDIF' commands to end the 'IF's. Another type of a loop is a 'DO...LOOP'. You tell it to do something continuously until a pre determined condition is met. You exit a 'DO...LOOP' with the 'EXIT...IF' command. Sometimes when writing a program, you may accidentally write loops without an exit. To stop the program and return to the editor, press the CONTROL, ALTERNATE and SHIFT keys simultaneously. This is called a 'BREAK'. lets look at an example of a 'DO...LOOP' (EX211). DO !Starts our loop CLS !Clear the screen INPUT "Please enter a number between 1 and 10 ",NUM% !Gets NUM% IF NUM%=3 THEN !If the number is 3 PRINT "You guessed my lucky number!" !Then print this PAUSE 300 !Pause for 6 seconds ELSE !if it isn't 3, then do this PRINT "Wrong. Please try again..." PRINT "Press any key to continue..." KEY=INP(2) !Wait for any key to be pressed ENDIF IF NUM%=>11 THEN !If you enter a number we don't want then PRINT "You didn't follow instructions." PAUSE 300 ENDIF EXIT IF NUM%=>11 !This exits our 'DO...LOOP' when NUM%=>11 LOOP Another type of looping can be done with the 'FOR...NEXT' command. It usually starts a counter and processes the commands between the FOR and the NEXT as long as the counter is still valid. For example: FOR NUM%= 1 to 10 states that our integer variable (NUM%) will equal 1, then 2, then 3, etc. up to 10. When the program encounters the NEXT command it returns to the FOR to process the commands between FOR and NEXT again. For example (EX212): FOR NUM%=1 to 10 PRINT PRINT NUM% !This will print our variable NEXT NUM% !This sends our program back to the first line Each time through, NUM% will be printed so your screen will look like this 1 2 3 ETC. Another type of loop is the 'REPEAT...UNTIL' loop. REPEAT starts the loop and it continues until the condition set in the UNTIL command is true. For example (EX213): REPEAT !Starts the loop CLS INPUT "Please enter a number between 1 and 10 ",NUM% !Gets NUM% IF NUM%=5 THEN !If the number input=5 then PRINT "Good guess!" PAUSE 300 ELSE PRINT "Wrong! Press any key to try again..." KEY=INP(2) ENDIF UNTIL NUM%=5 !This exits if the number was 5 Another command essential to programming is the 'GOSUB' command. This directs your program to a particular routine that you may want to perform any number of times. The 'GOSUB' command can be abbreviated '@' and the location you want your program to go to must begin with 'PROCEDURE'. To return from the 'PROCEDURE' to your program, simply end the PROCEDURE with 'RETURN'. That sends you back to the line after the GOSUB command. This is best demonstrated with an example (EX214): DO CLS PRINT AT(10,10); !Print a blank line to move 10,10 INPUT "Please enter a number (1 - 25) ",NUM% IF NUM%=>1 AND NUM%=<25 THEN GOSUB Check_number !Execute PROCEDURE named Check_number ENDIF EXIT IF NUM%="0" !Exits loop if we enter 0 LOOP EDIT !Return to the editor after exiting the loop ' PROCEDURE Check_number CLS PRINT AT(30,12); PRINT "You entered "NUM%" ..." PAUSE 200 RETURN !Go back to our loop to get another number One more type of loop to learn and then we're finished with this lesson (Whew!). This is the 'WHILE...WEND' type of loop. WHILE sets up a condition and if it's true it processes all the commands between WHILE and WEND (WEND stands for WHILE END) until the WHILE condition is met. The major difference between the 'WHILE...WEND' loop and the other types is that it's possible for the 'WHILE...WEND' to never be processed if the WHILE condition isn't true. With the others, they always process their loops at least once and look for an EXIT. An example follows (EX215): FOR NUM%=1 to 15 !Set up our counter CLS PRINT AT(25,12);"Our number is now "NUM%"..." PAUSE 100 WHILE NUM%=10 !Do this ONLY while NUM%=10 PRINT AT(25,14);"Now in the 'WHILE...WEND' loop..." PAUSE 300 EXIT IF NUM%=10 WEND !End the while loop NEXT NUM% !Return to our counter Notice that the ONLY time our WHILE...WEND loop is executed is when our variable is equal to 10. The other times, it never executes the loop. Enter all these commands and play with them. You'll learn a lot just by experimenting with them. Also, read about these commands in your GFA Basic owners manual, their examples should help serve to clarify what you've learned here. Class 3 This lesson we're going to learn a little about making our programs a bit more graphically pleasing. We've already learned how to use the PRINT command to place characters on the screen so lets move on to another way to put our text on the screen. The DEFTEXT command (stands for 'define text') allows us to change several characteristics of our text. After you use the DEFTEXT command, you can use the TEXT command at any time in your program to place your custom formatted TEXT on the screen. Your TEXT will always appear in the same style, color and size as the last DEFTEXT command you issued. To change the style (or color and size), simply enter the DEFTEXT command again. The TEXT command is similar to the PRINT AT command except that instead of using the column and row to define where you'll PRINT, you now must use the 'pixel' location. A pixel is only a dot on the screen and in medium resolution, the ST has 640 dots or pixels horizontally and 200 pixels vertically. When you issue the TEXT command with the pixel location to begin your TEXT at, remember that the location you provide represents the lower left of the first letter in your TEXT. The usage of the DEFTEXT command is as follows: DEFTEXT A,B,C,D . A,B,C & D are simply numeric variables you supply to tell GFA how you want your TEXT to look. The first variable (A), is the number of the color you want your TEXT in (0-3 for medium resolution, 0-15 for low and 0-1 for high). The second variable (B), defines the style of TEXT as follows: 0 - normal, 1 - bold, 2 - light, 4 - italic, 8 - underlined, 16 - for outlined and to get any combination of these, you simply add the values together (i.e. Bold italics would be 1 for bold + 4 for italics = 5). The third variable (C), may be 0,90,180 or 270 and it defines the rotation of the TEXT in degrees (i.e. 180 is upside down). The last variable (D), defines the height of the characters in pixels with 4 being very small and 32 being large. Lets look at an example to help us ingest all this (EX31): DEFTEXT 3,16,0,32 !Change the numbers and 'Play' TEXT 250,100, "Hello there!" PAUSE 200 EDIT We can also put graphic shapes on the screen rather easily by using the proper command and supplying the pixel coordinates where we want our shape drawn. Three commonly used commands for this are BOX, CIRCLE and ELLIPSE. The BOX command is used as follows: BOX A,B,C,D where A and B represent the pixel locations of the upper left hand corner of the box and C and D represent pixel locations for the lower right hand corner. You may also draw rounded corners on a box by simply placing an 'R' in front of the command (i.e. RBOX A,B,C,D). Lets draw a box (EX32): BOX 100,50,540,150 PAUSE 200 CLS RBOX 100,50,540,150 PAUSE 200 EDIT The CIRCLE command is similar:CIRCLE A,B,C where A and B are the pixel locations for the center of the CIRCLE and C is the radius (in number of pixels) (EX33). CIRCLE 320,100,140 PAUSE 200 EDIT Again, the ELLIPSE command is easy to use: ELLIPSE A,B,C,D where A and B are the pixel locations for the center (just like CIRCLE) and C is the length of the horizontal axis and D is the length of the vertical axis (EX34): ELLIPSE 320,100,140,30 PAUSE 200 EDIT Now, lets move on to the DEFFILL and FILL commands. DEFFILL stands for define fill and it just allows us to define a fill pattern and color of our choice. FILL is used to fill an area that we provide the coordinates for with the pattern we defined in the DEFFILL command. Usage is: DEFFILL A,B,C where A is the color to use (same as before) and B and C are the patterns. Many patterns are available so I'll refer you to your GFA owners manual as they have pictures of all the available patterns and their corresponding numbers. Usage of the FILL command is as follows: FILL A,B where A is the horizontal pixel location to begin the FILL and B is the vertical pixel location. If you're filling an enclosed are (BOX,CIRCLE or ELLIPSE), be sure your coordinates are inside the shape and not just on the border as the FILL command will work on the border. It simply fills all areas of the same color with your pattern. If your shape isn't fully closed, it can also 'leak' out to the rest of the screen. Now an example (EX35): BOX 100,50,540,150 DEFFILL 1,2,9 FILL 101,51 PAUSE 200 EDIT Another way you can FILL a shape that's much faster is to add a 'P' in front of the shapes command (PBOX,PCIRCLE or PELLIPSE). You must issue the DEFFILL statement BEFORE the PBOX or FILL or else it will have no effect (a PBOX without a DEFFILL first would simply draw a BOX). As in the BOX command, you may also use the 'R' for rounded corners with the PBOX command (i.e. PRBOX) to get a filled BOX with rounded corners. Lets do another example (EX36): BOX 100,50,540,150 DEFTEXT 3,4,0,13 TEXT 265,100,"Plain 'BOX'" @NEW_SCREEN !Remember our GOSUB? CIRCLE 320,100,80 TEXT 265,100,"Plain 'CIRCLE'" @NEW_SCREEN ELLIPSE 320,100,140,30 TEXT 265,100,"Plain 'ELLIPSE'" @NEW_SCREEN DEFFILL 1,2,16 PBOX 100,50,540,150 TEXT 265,160."Filled 'BOX' (PBOX)" @NEW_SCREEN PCIRCLE 320,100,80 TEXT 265,160,"Filled 'CIRCLE' (PCIRCLE)" @NEW_SCREEN PELLIPSE 320,100,140,30 TEXT 265,160,"Filled 'ELLIPSE' (PELLIPSE)" @NEW_SCREEN PRBOX 100,50,540,150 TEXT 265,160,"Filled BOX with rounded corners (PRBOX)" PRINT AT(28,23);"Press any key to continue..." KEY=INP(2) EDIT ' PROCEDURE NEW_SCREEN PRINT AT(27,23);"Press any key for next shape..." KEY=INP(2) CLS RETURN Lets go on to another helpful graphic command and that's the GRAPHMODE command. GRAPHMODE determines how the graphic shape you place on the screen will affect other shapes already there. Usage is: GRAPHMODE A where A may be 1,2,3 or 4. 1 is the default mode and it indicates 'replace', in other words, whatever you put on the screen covers up whatever was already there. 2 is 'transparent' mode, your new graphic allows the old to show through. 3 is called 'XOR' and it sort of inverses whatever is there. For a better explanation of 3 and an explanation of 4, please refer to your GFA manual (they're seldom used). We'll combine an example of this command later with some of the others. Two other graphic commands that work hand in hand with those we've already learned are the DEFLINE (define line) and LINE commands. The DEFLINE command must be issued before the LINE command and its' usage is: DEFLINE A,B,C,D where A defines the style (1 - 6, see your GFA manual), B defines the lines width in pixels and C and D define the beginning and ending styles of the LINE (i.e. 0-normal, 1-an arrow, 2-rounded). The LINE command draws a LINE in the style defined in DEFLINE between two points. Usage is: LINE A,B,C,D where A and B are the pixel locations of the beginning of the LINE and C and D are the ending pixel locations of the LINE. Time for an example (EX37): FOR X=1 TO 3 DEFLINE 1,10,X,X LINE 100,100,540,100 PAUSE 200 NEXT X EDIT Another important graphic command is DRAW or DRAW TO. Usage is DRAW A,B to DRAW a single pixel at location A,B or DRAW A,B TO C,D to DRAW a line between the two pixel locations (A,B and C,D). It's very similar to the LINE command except that you may continue the line you're drawing by adding additional 'TO's in the command. The PLOT command is identical to the DRAW command when you only supply it with A,B. They both DRAW a single dot (pixel) at the location you specify. Lets do an example (EX38): DRAW 10,10 TO 630,10 TO 630,190 TO 10,10 PAUSE 200 EDIT This draws a triangle between the points we provided. Now to add a little COLOR to our programs. The COLOR command determines what color will be used when you issue the BOX, CIRCLE, ELLIPSE, LINE or RBOX commands. It's use is very simple: COLOR A where A is one of the available colors for the resolution you're in (0-15 for low, 0-3 for medium and 0-1 for high). Lets venture into a few of the STs' more unique commands like the mouse. Two very easy commands that affect the mouse are HIDEM (hide mouse) and SHOWM (show mouse). Using them is as simple as (EX39): HIDEM ? "No mouse on screen now..." PAUSE 300 SHOWM ? "Here's your mouse back..." PAUSE 300 EDIT A command that controls the shape of the mouse is the DEFMOUSE (define mouse) command. Usage is: DEFMOUSE A where A can be any number between 1 and 7 to choose any of 7 predefined mouse shapes. Advanced users can also use this command to create their own mouse shape but we'll keep it simple here. Run the following example (EX310): FOR X=1 TO 7 DEFMOUSE X PRINT AT(25,11);"This is mouse shape "X"..." PAUSE 300 NEXT X EDIT Another mouse command is simply MOUSE. This command reads the horizontal and vertical locations of the mouse pointer and it also reads the status of the mouse buttons. Usage is: MOUSE A,B,C where A is the horizontal pixel location, B is the vertical pixel location and C is the current status of the mouse buttons. C can be 1 of 4 values (0-3). 0 indicates no buttons are being pressed, 1 indicates the left button is being pressed, 2 indicates the right button is being pressed and a 3 indicates both the left and the right buttons are being pressed together. An example (EX311): PRINT AT(27,23);"Press right mouse button to exit..." DO MOUSE A,B,C VSYNC !What's this? Read below... PRINT AT(1,1);"Horizontal location - "A"" PRINT AT(1,2);"Vertical location - "B"" PRINT AT(1,3);"Button status - "C"" EXIT IF C=2 !Set our loop exit condition LOOP EDIT I dropped a new command on you while you weren't looking! The VSYNC command allows you to coordinate your screen updates with the refresh rate of the ST. It gets very complicated but lets just say that anytime you get a real bad screen flicker, this command will usually help out. To see what I mean, go back to the previous program and put a remark symbol (') in front of the line with the VSYNC and see what the program does without its' help. Another way to read just a particular item from the mouse (i.e. if you only need 1 of the 3 MOUSE variables), is to use another form of the MOUSE command. These are MOUSEX, MOUSEY and MOUSEK. As you may have guessed, MOUSEX reads only the horizontal pixel location while MOUSEY reads the vertical pixel location and MOUSEK reads only the mouse button status. An example (EX312): K=MOUSEK HIDEM PRINT AT(28,11);"You can't see the mouse," PRINT AT(28,12);"but right click to exit." REPEAT UNTIL K=2 EDIT With the preceding commands we've learned, you can actually begin to write some of your own 'GEM' type routines. Examine the following program and make sure you understand it all as it will help you to build your own routines (EX313). Graphmode 2 !'Transparent' drawing mode Color 3 !Sets color for drawing to color 3 Defline 1,18 !Defines the line as solid and 18 dots thick Deffill 2,2,4 !Set a solid fill in color 2 Prbox 20,20,620,180 !Puts a filled,rounded box on screen Rbox 20,20,620,180 !This draws the thick border Defline 1,6 Rbox 280,147,360,163 !Our exit box Deftext 1,0,0,32 !Set text to big and color 1 Text 260,70,"Sample !" Deftext 3,4,0,13 Text 100,90,"This is how you could build your own 'Dialog' type boxes!" Text 210,110,"Click in the box to exit..." Print At(39,20);"Exit!" Defmouse 3 !Defines mouse shape as the hand Do Mouse A,B,C !Reads mouse position and button status If A=>286 And A=<354 And B=>153 And B=<157 Then If C=1 Then !If mouse is in the right place, check button status X=1 Endif Endif Exit If X=1 !Exit loop if all was correct Loop Deffill 1,2,8 Graphmode 3 !Sets graphmode to 'XOR' (Read the book!) Prbox 280,147,360,163 !Turns our exit box inverse Pause 10 !Pauses momentarily Edit That's all for this lesson but as always, remember that using these commands is the key to learning them. Have fun! Class 4 We'll move on now to several commands that are very necessary in any programing environment. Lets begin with two simple and easy yet very powerful and time saving commands, SGET and SPUT. They stand for 'Screen Get' and 'Screen Put' respectively and all they do is copy the entire screen into a character string variable for use later in your program. The advantage here is speed as the whole screen can be almost instantly saved or replaced but the disadvantage is that each screen you reserve with SGET uses 32K of memory. Example (EX41): Deftext 1,5,0,32 Text 220,70,"Screen #1" Sget Screen1$ Pause 50 Cls Text 220,130,"Screen #2" Sget Screen2$ Pause 50 @Flip_them Edit ' Procedure Flip_them Repeat Hidem For X=30 Downto 1 Vsync Sput Screen1$ Pause X Vsync Sput Screen2$ Pause X Exit If Mousek<>0 Next X Until Mousek<>0 Showm Return If you don't need the entire screen copied into a variable, you could use the GET and PUT commands to copy just a selected portion of the screen into a variable. Usage is: GET A,B,C,D TEMP$ where A and B are the upper left horizontal and vertical pixel locations, C and D are the lower right hand corner pixel locations and TEMP$ is the character string variable you supply to hold that particular section of the screen. Usage of the PUT command is exactly the same except you only need provide the A and B locations and of course it places the variable TEMP$ at the locations you provide. Lets look at an example (EX42): Circle 320,30,25 Get 294,4,346,56,Temp$ Pause 50 Put 50,50,Temp$ Pause 50 Put 100,100,Temp$ Pause 50 Put 400,150,Temp$ Pause 200 Edit Two other commands that are very easy to use are DATE$ and TIME$. They simply provide you with the date and time as your ST currently has it (i.e. if you don't have a clock or haven't set the time via the CONTROL.ACC, you'll probably show Nov 25, 1985). No additional items are needed with either command so they're use is easy. Example (EX43): Print At(25,11);"Current time is ";Time$;"" Print At(25,12);"Todays' date is ";Date$;"" Pause 200 Edit Another frequently used routine we need to learn is the 'READ...DATA' routine. When you use the READ command, you use any variable you choose and you're telling your program to READ the value of that variable from a list you provide in a DATA statement. You MUST be sure to use the correct type of variable to read the type of data you're using. If you tell the program to READ X, be sure you only have numeric values in your DATA statement. If you tell it to READ X$, then you may use characters or whatever in your DATA statement. Example (EX44): For A=1 To 10 Read X Print At(23,12);"The value of 'X' is now ";X;"..." Pause 50 Next A Edit Data 10,20,30,40,50,60,70,80,90,100 If we wanted to use some of our variables again, we could issue the RESTORE command which tells GFA that it can start back at the first DATA item the next time we issue a READ command. For example (EX45): For A=1 To 10 Read X$ Print At(28,11);"Hello ";X$;" ! " Pause 100 If A=5 Then Print At(20,11);"Returning to first 'DATA' value..." Pause 200 Cls Restore Endif Next A Data Celia,Robert,Gordon,Hobart,Joe,Tom,Brett,Andy *** Please notice that even though we supply 8 *** names (data items), the routine only uses 5 of them because the RESTORE command sets the next READ back to the first DATA item. Okay, now to move on. So far we've been using the EDIT command in our examples to return us to the editor without having to click on the 'RETURN' box but when we actually write a program we can't end it that way. We need to know how to properly exit to the GEM desktop. There are several GFA commands that allow this, END closes all open files and terminates your programs execution. STOP will stop your program but if you're working with open disk files, it will not close those files (you may continue from the point you stopped by issuing the CONT command - stands for continue). QUIT and SYSTEM are another 2 commands to terminate your program and like END they will also close all open files but the big difference is that both of these will return you to the GEM desktop, even if you're using GFA. END will return you to the editor. (Sorry, no example here, type QUIT or SYSTEM while in GFA and run them to see what they do 8-) ...) Another helpful command is FRE(0). It reports the amount of free RAM available to you for GFAs' use at any given time. If you're writing a program it can help you determine how much memory you're using so you can make sure your program will function properly on any ST (i.e. a 520 ST with 512K of RAM). Here's an example of how to use it (EX46): X%=Fre(0) Print X% Pause 100 Sget Screen1$ X%=Fre(0) Print X% Pause 100 Edit There's also a command to let you know how much free space is on the disk you're using and that's the DFREE command. Usage is DFREE(X) where X is the value of the drive you want to check the free space on. X may be between 0 and 15 and 0 stands for the default disk, 1 is for drive A:, 2 is for drive B:, etc on up to 15. Example (EX47): X%=Dfree(1) Print X% Pause 200 Edit To see what files are actually on a disk there are two different commands you may use. One is FILES and the other is DIR. Both commands allow the conventional use of wildcards (? and *) and usage is FILES "A:*.*" or FILES "A:\TEST\*.BAS" or DIR "A:*.LST" etc. The difference between the two is the FILES command not only shows you the name of the files but also their creation dates and the file size while the DIR command only shows the names of the files. You may direct the output of either of these commands to other than the screen (for example to a file on disk in ASCII format) by specifying a TO file. FILES "A:*.*" to "A:XXX.XXX" or DIR "A:*.BAS" TO "A:GFA.DAT" etc. If you wanted, you may also direct the output to a printer by specifying "LST:" as the TO device. Ever want to know how to zip off some disk labels? Example (EX48): Files "A:*.*" Pause 300 Dir "A:*.*" Pause 300 Edit Other available commands to manipulate disk files are MKDIR and RMDIR for the 'make directory' and 'remove directory' functions. Usage is similar to DIR and FILES in that you must specify complete paths etc. MKDIR "A:\TEST" makes a directory (folder) on drive A: called 'TEST'. RMDIR "A:\TEST" removes a directory (folder) from drive A: called 'TEST'. You may also change your current path by switching into and out of directories (folders) by issuing the CHDIR command. Its' use is similar to the other disk type commands in that you must issue the pathname you want to change to. Usage is CHDIR "A:\TEST" to change to a folder called 'TEST' or CHDIR "\" to move back to the root directory of the disk you're using. To find out what directory you're currently in you may use the DIR$ command as follows: DIR$(x) where x may be 0-15 to represent the drive number (same as the DFREE command). If you have more than one drive connected and online, you can change drives by using the CHDRIVE command as follows: CHDRIVE X where x may again be 0-15 to tell GFA what drive to switch to. You may also rename files on disk by using the NAME command as follows: NAME "A:OLDFILE" AS "A:NEWFILE". Another helpful command to see if a file already exists on disk is the EXIST command used as follows: EXIST("Filename"). A value of -1 is returned if the condition is true (if the file exists) and a condition of 0 is returned if the condition is false. You may also delete a disk file with the KILL command as follows: KILL "A:TEST". You can use wildcards (? and *) to specify which files to delete but be careful! Okay, we've just had a lot of reading so lets do an example to show us all these various things in use (EX49): Rem Short disk files routines Chdrive 1 Print "Creating a file on disk called 'TEST'" Files "A:*.*" To "A:TEST" !Put list in file 'A:TEST' Print At(25,12);"Press any key for a directory of A:" Key=Inp(2) Cls Dir "A:*.*" !Directory to the screen Print X%=Dfree(1) Print "There are ";X%;" bytes available" Print At(26,24);"Press any key to continue..." Key=Inp(2) Cls Print "Now creating a directory (folder) called 'TESTDIR'" Mkdir "A:\TESTDIR" Chdir "A:\TESTDIR" Cls Print "Now in the directory we just made..." Files "A:*.*" Pause 150 Chdir "A:\" Cls Print "Now back in the root directory..." Files "A:*.*" Print Print "Notice our new directory called 'TESTDIR'?" Print "(Press a key when ready)" Key=Inp(2) Cls Print "Now copying our 'TEST' file to our new directory" If Exist("A:TEST") Then Name "A:TEST" As "A:\TESTDIR\TEST" Endif Cls Print "Here's a directory of what's in our folder now..." Files "A:\TESTDIR\*.*" Pause 100 Kill "A:\TESTDIR\TEST" Cls Print "Just killed our test file, here's another directory" Files "A:\TESTDIR\*.*" Pause 100 Rmdir "A:\TESTDIR" Cls Print "Just removed our directory, see?" Files "A:*.*" Print Print At(26,23);"Press any key to continue..." Key=Inp(2) Edit That's it for this lesson. Remember that practice makes perfect and the only way we all get any better is using all of these enough to at least be familiar with what they can do! Class 5 This lesson we'll learn a few more GEM commands and go a little deeper into some of the finer things in GFA. First on the agenda is the infamous little Alert Box that pops up when least expected. Alert boxes are very easy to use in GFA, in fact they're only one line commands. The command is (of course) ALERT but there are several variables we need to supply it to make it function properly. Proper use is: ALERT A,TEXT$,B,BUTTON_TEXT$,C where each of these is as follows: A is a variable between 0 and 3. It determines what (if any) predefined shape will appear in your alert box. A 0 indicates no shape, a 1 indicates an exclamation point, a 2 is a question mark and 3 is the stop sign. The next item (TEXT$), is the string of text you want displayed in the box. It may have up to 4 lines of text, each containing no more than 30 characters (including spaces) and the lines are separated by the '|' symbol (right under your delete key). The next variable (B), is the number of the button you want to become the default button, that is, the button that will be selected if the user just presses return. A 0 means no default (this forces a mouse click), 1,2 or 3 indicate buttons 1-3 since 3 buttons is the most you may have. The next variable (BUTTON_TEXT$), is of course the text for your buttons. Each button may have up to 8 characters and again they're separated by the '|' symbol. The last variable (C), is any variable you choose to contain either 1,2 or 3 (depending on which button the user selected) so you can have your program perform the appropriate function. Lets look at an example (EX51): Text$=" This is an example | of a 'STOP' box... " Alert 3,Text$,1," Great! |So what?",B% If B%=1 Alert 1,"Thank you !",0," Bye! ",Void Edit Endif If B%=2 Print "You must know this already!" Pause 200 Edit Endif Notice that in our second alert box, we used a variable called VOID for our returned value. VOID is a GFA command word and it's used when you need to supply a variable but the value returned is not needed. This could easily be any other variable but VOID is much faster (especially for the compiler). The next little GEM we'll learn (pun intended), is the fileselector routine. We've all seen them, the box that always pops up when we want to save or load a file. Again, this command is easy to use in GFA but you can experiment and make it much more powerful when you become familiar with its operations and functions. The command usage is: FILESELECT "Path", "Filename",TEMP$ where Path is the default path you wish to use (must be at least '\*.*') and filename is the default filename or mask (i.e. this may be '\*.BAS' to only show you files ending with .BAS, '\*.*' to show all files, etc.) and TEMP$ is the variable that will hold the string value of the file that was selected (if the user clicks on cancel, TEMP$ will equal ""). Lets take a closer look at exactly how this works in the following example (EX52): Repeat Fileselect "\*.*","*.*",Temp$ If Temp$="" Temp$="Cancel" Endif Print At(20,10);"You clicked on ";Temp$;"" Pause 150 Print At(20,23);"Press right mouse button to exit..." Pause 50 Cls Until Mousek=2 Edit Another command we need to know is the CHAIN command. This command allows you to load and run another GFA basic program but be forewarned that it deletes the program you currently have in memory. Usage is: CHAIN "TEMP$" where TEMP$ is the name of the file you want to load and execute. Here's an example (EX53): Print "Now saving this program..." Save "TEST.BAS" Print Print "Press and hold the left mouse button to exit..." If Mousek=1 Edit Endif Pause 100 Cls Print "Now loading and running the program..." Chain "tes*.bas" Notice we used another new command called SAVE? This command allows us to save any program currently in memory at any point in our program. Simply use SAVE "FILENAME" where FILENAME is what you want to call your program. You may also insert a 'P' in front of the SAVE command to make it PSAVE (PSAVE stands for Protected SAVE) and your program will work but it can not be listed in the editor. This means nobody (even you!) can look at your code once it's been PSAVEd so make sure you save a copy regularly first (just in case you decide to modify something, trust me). The LOAD command also functions the same as the SAVE command, LOAD "FILENAME" loads a program into memory. Here's a fun command that I know you've all been waiting for, the SETCOLOR command. Unlike the COLOR command which only lets us specify which color to DRAW in or to make graphics shapes in, the SETCOLOR command modifies the actual color registers in the ST in effect making new colors for you (sort of like the CONTROL.ACC does). A word of caution here, if you use this command and reset colors in a program, try to be courteous and set them back to what they were before you changed them. Have you ever used a program and when you went back to the desktop you had some really putrid looking colors there? Yuk !! You may use the SETCOLOR command either of two ways and neither is easy to figure out so here goes: SETCOLOR X,A ",Nam$(X) Exit If Nam$(X)="End" Or Nam$(X)="END" Or Nam$(X)="end" Cls Next X !First we get ALL our names (up to 50) Open "O",#1,"NAMES.DAT" !Now we print them all to disk For X=1 To 50 Print #1,Nam$(X) !Each time through it increments NAM$(x) Exit If Nam$(X)="end" Or Nam$(X)="End" Or Nam$(X)="END" Next X !Notice it exits if 'End' was in there Close #1 ' Rem Now to see how EOF is used ' Open "I",#1,"NAMES.DAT" !Open to input from disk For X=1 To 50 Exit If Eof(#1) !Exit if end of file #1 is reached Input #1,Nam$(X) !Input each item, 1 at a time Next X X=X-2 !Do you know why I subtract 2? View_them: Cls Print Print "There are ";X;" names in this file, which do you want to see"; Input Y If Y=0 !Make sure we have the one you want to see Print At(30,11);Nam$(Y) !Prints your choice Print At(27,24);"Press any key to continue..." Key=Inp(2) Goto View_them !Keeps viewing until 'Y' is outside of 'X' Else Edit Endif Routines like this can be easily added to and expanded and turned into a full blown name and address type of database with very little else needed to make it the way you want it. One important thing to remember when you start working with a lot of variables is that you may only dimension (DIM) a variable once UNLESS you use the ERASE command to erase the variable and its' associated dimension. ERASE A$ would erase all your variables and allow to to redimension it and reuse the variable for something else. Another way to ERASE or release your variables is with the CLEAR command. Be careful when you use CLEAR though as it sets all numeric variables to 0 and all string variables to "" (nothing!). If you just want to CLEAR certain variables you can use the abbreviated command CLR by specifying what you want to CLR (i.E. CLR A$,B$,NAM$,X,Y). Another valuable little tidbit is the CHR$ function. This function converts characters the ST is capable of producing (but doesn't have the keys for) so you can display them in your programs. With CHR$ you can display most of the ST's 255 characters. Usage is CHR$(X) where X is the ASCII number of the character you want to produce (refer again to appendix C of your GFA owners manual). Lets try another example (EX66): Print At(1,8); For X=128 To 255 !These are the numbers we'll show Print " ";Chr$(X);""; !Print them Next X Print At(18,22);"Did you know you had all these keys?" Print At(24,24);"Press any key to exit..." Void Inp(2) Edit Another necessary command is the RANDOM command. It generates RANDOM numbers which you'll sometimes need. Usage is: RANDOM(X) where X is the upper limit (number) you want RANDOM numbers generated for. It always gives you numbers between 0 (inclusive) and X (exclusive). The following example simulates the RANDOM roll of a die (EX67): Print At(24,24);"Press any mouse button to quit!" Do X=Random(6)+1 !See below Print At(39,11); Print X Pause 50 Exit If Mousek<>0 Loop Edit The reason the '+1' is there is because with RANDOM(6), you'll get 6 RANDOM numbers between 0 and 5 so we add 1 which makes our numbers between 1 and 6! Another handy command is the UPPER$ command. Its' purpose is to convert any string variable to all uppercase characters. Usage is: UPPER$(A$) where A$ is the variable you supply. Examine the following example (EX68): Top: Cls Print At(1,11);"Please enter some lowercase text and press return -> "; Form Input 25,A$ !Get up to 25 characters Print At(36,13);"Thanks!" Pause 75 B$=Upper$(A$) !Convert them to uppercase Print At(1,15);"Here's what you entered -> ";A$;"" !Print originals Print At(1,17);"Here's after 'UPPER$' fixed it to all capitols -> ";B$;"" Print At(10,24);"Press left mouse button to do it again or right button to exit..." Repeat Exit If Mousek=1 If Mousek=2 Edit Endif Until Mousek<>0 Goto Top This wraps up another lesson, we're getting there. We've already discussed the majority of the commands available to us in GFA however, I've held off on some of the juicier ones till the end. If you're studying these examples and experimenting with the code, you're learning. Use your GFA manual to refer to their examples once you understand the basic concepts of the commands. When we get to the more powerful functions (read, more complicated), being able to interpret the manual and their examples will almost be a necessity. Happy coding!! Class 7 We're going to move now into some of the commands GFA has available that you may not fully understand why they're even needed. Let me assure you, at one time or another some of these more obscure commands can come in quite handy indeed. As with the other lessons, use the examples and explanations here in conjunction with your owners manual to get a really good grasp on the concepts involved. Don't be afraid of experimenting with the various commands as you'll discover a lot of the creativity process is derived from discovering new things you (and GFA) can do! First is the ASC function. Its' purpose is to determine the ASCII value of the first (or only) character in a string. Usage is: ASC(X$) where X$ is any variable name you supply. Lets look at an example (EX71): A$="Tom" Print "The original variable is ";A$;"" Print B=Asc(A$) Print "After using the 'ASC' function, the value is ";B;"" Pause 200 Edit This will print '84' as 84 is the ASCII value for the capitol 'T' (refer to appendix C for the entire list of ASCII values). Another similar function is VAL. You use it just like ASC, in other words, VAL(X$) where X$ is a variable you supply. What the VAL function does is convert the string variable into a numeric value as far as possible. It starts at the leftmost position of your string and converts any numbers into a numeric value until it encounters an alpha character (then it gives up). Lets look again at an example (EX72): A$="Tom123" B$="2003 Bob White Ct." Print "Variable A$ is originally ";A$;"" Print Print "Variable B$ is originally ";B$;"" A=Val(A$) B=Val(B$) Print Print "After using the 'VAL' function on A$, its' value is ";A;"" Print Print "After using the 'VAL' function on B$, its' value is ";B;"" Pause 300 Edit The numeric value of A$ will be 0 (nothing) as 'Tom123' has no numbers in the leftmost position before the alpha characters. The numeric value of B$ will be '2003' as it encounters those numbers before encountering the alpha characters. Another form of the VAL function is VAL? and you use it the same way you use VAL. It will tell you how many characters can be converted if you use the VAL function. Two more useful commands (at least for programming), are TRON and TROFF. They stand for Trace On and Trace Off and they do exactly as their name implies, they 'trace' your program while it's running displaying every command as it performs them. This can be very helpful in that you'll be able to see exactly where your program may not be doing exactly as you intended it to do. To use them, simply insert TRON in your program at the point where you want it to start showing the commands and TROFF where you want it to stop. They do slow down program execution considerably so be sure you get rid of them before you pass your program on to anyone else. Remember, they're just a programming (sort of a debugging type) of tool. Also, if you're using the GFA Compiler to compile your programs into stand alone programs, they will not compile with TRON and TROFF in them. Lets see how they work (EX73): Tron For X=1 To 25 Print X Pause 25 Next X Troff Cls For X=1 To 25 Print X Pause 25 Next X Edit Another short but useful function is FIX. You use it like this: FIX(X) where X is a numeric variable or a number. What it does is chop off any decimal portion of the value and leave you with the integer (whole number) portion. Example (EX74): A=2.666 Print "Original value of 'A' is ";A;"" Print B=Fix(A) Print "After using the 'FIX' function, the value is ";B;"" Pause 300 Edit GFA also has a function that's just the opposite of FIX and that's FRAC. It's used exactly the same way, FRAC(X) where X is a numeric variable or number you provide. What FRAC does, is throw away the integer portion of the value and keep only the decimal portion. Now it wouldn't make much sense to try a command like this: FRAC(X%) - do you know why? Right, the '%' sign indicates the number is already an integer variable (no decimal). Lets look at another example (EX75): A=2.666 B=Frac(A) Print "The original value of 'A' was ";A;"" Print Print "After using the 'FRAC' function, the value is ";B;"" Pause 300 Edit There's also a way we can store our current program in ASCII format and that's with the LIST command. Using it is simple, just LIST "Filename" where Filename is what you want to call your ASCII disk file of the program. If you don't provide a 'Filename', LIST will simply LIST the program to the screen, not the disk. By placing an 'L' in front of the LIST command, you can send a listing to your printer if you have one attached. If not, be prepared to wait about 30 seconds or so while the system figures out it's not there. Of course when you use the LLIST command, you needn't provide a Filename. As long as we're on the subject of placing the 'L' in front of commands to direct their output to the printer, lets discuss a few more. (I believe the 'L' is a carry over from the days when all printers were called 'Line Printers', therefore the 'L' in front of the command - just my theory though). You can place the 'L' in front of the PRINT command (LPRINT "Text") and your 'Text' will be printed on the printer instead of the screen. Another somewhat useful command if you're working with graphics is the HARDCOPY command. This performs the identical function to pressing 'Alternate Help' from the desktop, in other words is does a 'screen dump' of what's on your screen. The next function we'll examine is the SPC function. It stands for 'Space' (I think ??) and it's very easy to use. Usage is: SPC(X) where X is the number of spaces you want to print. SPC ONLY works with the PRINT command. Lets look at an example again (EX76): Print "Tom";Spc(10);"Hayslett" Pause 200 Edit Pardon me for using my name in these examples but then I don't know who is doing this now so it would be kind of tough for me to use yours huh? Anyway, lets move on to the SQR function. Guess what it does? Square roots. You use it like this: SQR(X) where X is the number you want the square root of. A simple example follows (EX77): X=16 !Change this to see what happens Y=Sqr(X) Print "Original value of 'X' is ";X;"" Print Print "After using the 'SQR' function, the value is ";Y;"" Pause 300 Edit Next in line is the STR$ function and it's used to transform a value into a character string. Usage is: STR$(x) where X is a numeric variable you supply (this is starting to sound like a broken record huh?). This function (STR$), will convert numeric values in any format (i.e. hexadecimal, binary or decimal) but to keep it simple, lets do a simple example (EX78): A=526 B$=Str$(A) Print "This is the numeric variable 'A'-> ";A;"" Print Print "This is a string variable now with this string -> ";B$;"" Pause 300 Edit Another useful function is STRING$. You use it to easily repeat strings when you need multiple output of specific items. Usage is: STRING$(A,A$) or STRING$(A,B) where A is the number of times you want the string repeated and A$ is the character string you want to repeat. B represents a number value for the ASCII value of the character you'd like to repeat. Lets do another example (EX79): A$="Tom" Print String$(3,A$) Pause 200 Edit This is easy as it prints 'TomTomTom'. The ASCII value of a capitol 'Z' is 90 (from appendix C) therefore if we use the command like this (EX710): Print String$(10,90) Print Print "This is using the 'STRING$' function and ASCII codes...(90='Z')" Print Pause 100 A$=Chr$(244) B$=Chr$(245) Print String$(79,A$) Print String$(79,B$) Print Print "These are ASCII codes 244 and 245, neat huh?" Pause 300 Edit Another useful command is SWAP (this IS referring to programs too!). Usage is: SWAP X,Y where X and Y are the values you want to exchange (SWAP). You may only SWAP variables of the same type (i.e. you can NOT do this: SWAP X,A$ because they are different types of variables) but you may SWAP any like types of variables. This would be fine: SWAP A$,B$. Just remember that when you SWAP variables, you also SWAP their dimensions (remember the DIM command?). Lets look at another example (EX711): X=10 Y=20 Z=1 Top: Print Print "Value for 'X' -> ";X;" Value for 'Y' -> ";Y;"" Print Print "Getting ready to perform the function 'SWAP' on 'X' and 'Y' ..." Swap X,Y Pause 150 If Z=4 Edit Endif Inc Z Goto Top Another easy function to use is TAB. Like the SPC function, TAB only works with the PRINT command (or 'LPRINT'). Usage is: TAB(X) where X is the column number you want to TAB to. Another example (EX712): Print Print Tab(35);"GFA Basic !" Pause 150 Edit Another GFA function is the INKEY$ function. All it does is read a character from the keyboard. This may also be used where we've been using 'Key=INP(2) or VOID INP(2)' to wait for a key press from the user. Look at the example (EX713): Print At(20,11);"Press any key to return to the editor..." Repeat Until Inkey$<>"" Edit On to bigger and better things! This is one of my favorites as I use it a lot and I see a lot of programs that could benefit by it. It's the INPUT$ function. Usage is: INPUT$(X) where X is the number of characters you want to read. When you use INPUT$ as in the following example, you can fix your programs so the user doesn't have to press return after entering a choice ( Y/N or a number, etc). If you assign it an 'X' value of 1, it only reads 1 character and then reacts. Look over the following example (EX714): Do Cls Print Print "Press any key or a 'Q' to exit.....-> "; X$=Input$(1) Print Tab(38);X$ !This shows the key they pressed Exit If X$="Q" Or X$="q" !Exit if they enter a q or Q Print At(10,10);"You entered a ";X$;"" Pause 100 Loop Edit Lets go through this together for a moment. First we're setting up a DO...LOOP so we know we'll need some type of EXIT IF condition. Next we clear the screen and ask the user to press any key. The 'X$=INPUT$(1)' only allows 1 key to be pressed and no return is needed so it reacts. Then we TAB out to column 38 and PRINT the key they pressed (X$). This is optional but if you don't do it, the INPUT$ function will not show the users key press. Then we simply simply check X$ to see if it equals 'Q' or 'q' (some folks leave their CAPS LOCK on all the time) if it doesn't, we print what they entered and do the loop again. When they enter a q, they return to the editor. We already learned a little about the INPUT and INPUT #X commands but if you experimented with them (which you DID do right?), you probably found out that INPUT doesn't like commas'. We can fix that though, simply add LINE in front of INPUT and you have the LINE INPUT function that works just like INPUT except it just loves commas (and most other oddball characters too!). Now if you use LINE INPUT and then PRINT that line to disk using the PRINT #1 command, you'd better read it back in with a LINE INPUT #1 command. Lets do an example of entering strings with commas and odd characters (EX715): Print At(1,10); Line Input "Enter something with commas'...",A$ Print Print "You entered '";A$;"'" Pause 200 Edit That was easy huh? So is the last command for this lesson (Whew!). This is the LOCAL command and all it does is allow you to declare a variable as a LOCAL variable, in other words, you can use the same variable name inside a Procedure that you use in your program as long as you issue the LOCAL command first. You have to do this so GFA can keep the proper values stored in the proper variables. Lets look at one more example (EX716): A=100 Print Print "Outside the procedure, A is equal to ";A;"" Pause 100 @Try_it Edit ' Procedure Try_it Local A A=50 Print Print "Inside the procedure, A is equal to ";A;"" Pause 100 Return That's it! I know, finally. My hands are sore from typing as I'm sure yours must be getting also. Anyway, until the next lesson, keep plugging away, we're almost there! Class 8 Lets begin by getting some of the remaining 'odds and ends' commands out of the way so we can press on to some routines. First command we'll look at is the ABS function and its' purpose is to return the absolute value of a numeric variable you supply. Usage is ABS(x) where 'x' is any numeric value or variable. The absolute value of any number is always equal to or greater than zero. Lets look at an example (EX81): X=-17 Y=17 Print Abs(X) !Both will return 17! Print Abs(Y) Pause 200 Edit Next is the LEN function. Its purpose is to determine the length of a string you supply. Usage is LEN(X$) where 'X$' is of course your string or character string variable. Look at the following example (EX82): X$="Hello there !" Print Len(X$) !Prints the 'length'(LEN) of 'X$' - 13 Pause 200 Edit The above example prints 13 as the LEN function counts every character including the spaces and punctuation. Next is the LOF function. LOF stands for length of file and it helps you determine how long one of your files are. You must first OPEN a channel then you may use the LOF function to determine the files length. Run the following example and notice that it prints the LOF twice, once when the file is empty and then again after we write a short string to the file (EX83): Open "O",#1,"TEST" !Open channel #1 for a file named 'TEST' Print Lof(#1) !Should print 0, file is empty ! Print #1,"Hello there !" !Put something in it... Print Lof(#1) !Now our length is 15 ! Close #1 Pause 200 Edit The next 4 commands all function identically and do pretty much the same thing just on different parts of variables we provide. We'll look at them as a group since they're so closely related. They are LEFT$, RIGHT$, MID$ and INSTR. Their purpose is to help you determine the contents of a character string variable and the first two (LEFT$ and RIGHT$) are used exactly the same way: LEFT$(X$,A) where 'X$' represents the variable you provide and 'A' represents any whole number you provide. What it does is count 'A' characters to the left in your string variable and return just that portion of the string. RIGHT$ works exactly the same except from the right side of your string. Perhaps this short example will help (EX84): X$="Hello there !" Print Left$(X$,5) !This prints Hello (the left 5 characters of X$) Print Right$(X$,7) !This prints there! (the right 7) Pause 200 Edit Simple huh? Okay, lets move on to the third command, MID$. It returns a portion of a string you supply but it can take its portion from anywhere in the string, even the MIDdle. You use it as follows: MID$(X$,A,B). Notice we have one more variable here ('B')? That's because we have to tell it where to start counting characters ('A') and how many to count ('B'). Lets see MID$ in action (EX85): X$="Hello there Tom" Print Left$(X$,5) !Prints 'Hello' Print Right$(X$,3) !Prints 'Tom' Print Mid$(X$,7,5) !Prints 'there' Pause 200 Edit MID$ in the above example started at the seventh position in our string and took the next 5 characters. Neat huh? Now, for the last of the 4 commands, INSTR. It's a little different than the first 3 we learned but it IS related. Its purpose is to help you determine if a string you provide is contained within another string (INSTR - IN STRing). Usage is INSTR(A$,B$) and all it does is check to see if 'B$' is present in the 'A$' string and if so, returns its position (for further manipulation with LEFT$, RIGHT$ or MID$). Lets look at another example (EX86): A$="This is only a test!" B$="only" Print Instr(A$,B$) !Should print 9 Pause 200 Edit It prints 9 because the string 'only' IS in the first string (A$) and it begins at the ninth position. Lets go on to a routine now... This is the ON BREAK, ON BREAK GOSUB and ON BREAK CONT set of commands and they let you control whether the CONTROL + SHIFT + ALTERNATE keys will 'break' the current program or how the program will react when a user tries to 'break' (stop) the program. To render the break keys useless simply enter the command ON BREAK CONT as it stands for on break continue and your program will just keep chugging away when someone presses the break keys. To turn them back on, just enter ON BREAK in your program and after that point they will react as usual (stopping the program). The ON BREAK GOSUB Procedure just tells your program that if the break keys are pressed, gosub to 'Procedure'. This is simpler than it sounds, look at the following (EX87): On Break Gosub Warning !'Warning' is our procedures name Do Print At(25,11);"Press the 'break' keys anytime..." Print At(26,13);"(CONTROL + SHIFT + ALTERNATE)" Loop Edit ' Procedure Warning !Go here if they press the break keys Cls Print At(25,11);"You're in the 'Break' Procedure now..." Pause 200 On Break !Turn the break keys back on... Cls Return Another helpful routine is the ON ERROR and ON ERROR GOSUB Procedure routines and yep!, you guessed it, they work very much like the previous set of routines except they direct your program to a particular location in the event an error occurs. Normal errors in GFA (i.e. division by 0), show you an error alert and terminate the program. You can prevent this from happening by using the ON ERROR commands (this is sometimes referred to as 'Error trapping' because that's what you're doing, 'trapping' errors and sending them to your procedure instead of allowing them to end the program). You MUST issue the ON ERROR GOSUB Procedure command BEFORE an error occurs for it to work and it's only good for the next occurrence of an error (1 time). You can issue the command again and it would then be good for the next occurrence of an error. GFA will even let you issue the command in your 'error trapping' procedure which effectively makes the command good for all errors. If for some reason you want the program to return to the normal error handling routines, just issue the ON ERROR command and any future errors will work as usual. There are several other commands that should (or could), be used in conjunction with the ON ERROR GOSUB Procedure commands so lets go over those before getting into an example. First is the RESUME command. Its purpose is to tell your program where to go to continue processing after an error has occurred. It may ne used 1 of 3 ways: RESUME, RESUME NEXT or RESUME 'Label:' . The first way (RESUME), sends your program right back to the line that the error occurred in. The second way (RESUME NEXT), sends your program to the line following the line the error occurred in. The third way (RESUME 'Label:'), directs the program to a 'Label:' just as the GOTO command does. Lets dig into the following example (EX88): X=1 !Set up our counter On Error Gosub Goof !Sets up where to go in case of an error Again: !A label to return to Print "Now attempting to divide 3 by 0 ..." Pause 100 !The pause must be BEFORE the error occurs Print 3/0 !3 divided by 0? This is an error, lets gosub Goof Edit Procedure Goof Cls Print "Oops, you can't divide by 0 !!!" Pause 200 On Error Gosub Goof !For our next error Inc X !Increment our counter by 1 If X=3 Cls Resume Next !Return to the line AFTER the error (Edit) Else !If X <> 3 Cls Resume Again !Return to the label 'Again:' Endif Return The next function we're going to examine also works with the ON ERROR routines and that's the ERR command. It's simply a variable that contains the number of the last error that occurred. Appendix B in the GFA Owners Manual contains a listing of the error codes by number and what they translate to. If an error occurs, you can PRINT ERR to see the number of the offending error. Check out this example (EX89): On Error Gosub Goof Print 3/0 !Our little divide by 0 error @Tom !Cause another error (Procedure not found - 19) Edit Procedure Goof Cls Print "Error number ";Err;" occurred..." Pause 200 On Error Gosub Goof Resume Next Return Another function that works with these error trapping routines is FATAL and it will only represent 1 of 2 values that indicate whether or not the error was FATAL (producing those infamous little cherry bombs across your screen). If FATAL contains a value of 0, the error was NOT FATAL but if it contains the value -1, kiss it goodbye...These 2 values (-1 and 0) are always used by GFA to determine a true/false condition where -1 is true and 0 is false. In fact, GFA has the 2 commands TRUE and FALSE for you to use if they're easier to remember than the -1 and 0. To see how FATAL, TRUE and FALSE work, lets look at another example (EX810): On Error Gosub Goof Error 100 !Force error number 100 Error 5 Error 32 Error 109 !Definitely Fatal if it really happens!! Edit Procedure Goof Cls Print At(25,12);"Error number ";Err;" occurred..." Pause 100 If Err=109 Fatal=True Endif ' This 'If' condition is never met because using 'Error 109' doesn't ' really cause the error to happen (or you'd see 9 little bombs 8-) If Fatal=True !Does Fatal = -1? Print At(18,12);"This is a 'Fatal' error (causes bombs!)..." Pause 200 Edit Else Print At(18,12);"This error isn't fatal, you may continue...." Pause 100 On Error Gosub Goof Cls Resume Next !Return to line AFTER the error Endif Return Enough with the errors (you'll never make any anyway right?). Another set of functions we'll learn are BIN$, OCT$ and HEX$. They all work the same, only the output is different and you use them as follows: BIN$(X) (or OCT$(X) or HEX$(X)) where 'X' is any numeric variable you supply. All three of these functions, convert your variable (X), to a string containing the binary (BIN$), octal (OCT$) or hexidecimal (HEX$) value of 'X'. Have you ever wondered what those values looked like? The following example will show you a few (EX811): For A=0 To 29 Cls B$=Bin$(A) !Convert 'A' to binary and store it in B$ Vsync Print At(20,11);"The number is ";A;" ..." Print At(20,13);"After BIN$, its' value is ";B$;" ..." Pause 25 Next A For A=0 To 39 Cls B$=Oct$(A) !Now do it for octal Vsync Print At(20,11);"The number is ";A;" ..." Print At(20,13);"After OCT$, its' value is ";B$;" ..." Pause 25 Next A For A=0 To 59 Cls B$=Hex$(A) !And finally, hexadecimal Vsync Print At(20,11);"The number is ";A;" ..." Print At(20,13);"After HEX$, its' value is ";B$;" ..." Pause 25 Next A Edit One final command for this lesson is the DEFLIST function. It stands for Define LISTing and it allows you to change the way your program looks when you use the LIST command. DEFLIST may be used with either of 2 values, 0 or any other. Usage is: DEFLIST 0 or DEFLIST 1 depending on what you want the LIST command to show. If you use 0, it lists all GFA command words in all capitol letters and all variables in lowercase letters and DEFLIST 1 is the same as the default (first letters of commands and variables capitalized only). The LIST command is used like this: LIST "" and it will send a current file listing to your screen. Look at the two screen examples of 'LISTing' used in the next routine (EX812): Deflist 0 !All capitols X=1 Top: Cls Print "Hello there!" Print At(24,24);"Press any key to continue..." Void Inp(2) List "" Pause 250 If X=1 Deflist 1 Inc X Goto Top Endif Edit That wraps up another lesson, hope you're enjoying soaking up all this good stuff!