This text is from the first ever magazine from Parco Electric in Honiton, Devon, a magazine for owners of the Texas TI-99/4A Home Computer, still relevant for anyone with one of the TI99/4a emulations such as MESS. This first issue was a co-production with Holland and the content is mostly translated from Dutch. Later issues were all Parco originated.
LOSS OF PROGRAM
Beware of hitting more than two keys together. You will be surprised if you do hit "FCTN .(period) 2" at the same time.
Then your program will be gone with the wind and you can start all over again (but hopefully without the same mistake).
The same will happen when you hit: "FCTN ,(comma) 3" "FCTN M 4" or "FCTN N 5"
IN PROGRAMMING TIME
Type in the next line in Extended Basic and you will get rid of that eternal blue screen.
CALL SCREEN(2) :: FOR X=0 TO
14 :: CALL COLOR(X,16,2) ::
NEXT X :: ACCEPT A
Press FCTN CLEAR and start programming in the way you always do, but watch out for errors, because they will turn your screen blue again.
Read the next part very carefully when you don't like to type this line over and over again. It can also be done with a recall of this formula when you give it a line number.
Type 30000 then
CALL SCREEN(2) :: FOR X=0 TO
14 :: CALL COLOR(X,16,2) ::
NEXT X :: ACCEPT A
and press ENTER.
Get the line back with FCTN REDO, remove the line number press ENTER and then FCTN CLEAR.
Now you can recall this line after each error as follows:
Type 30000 FCTN X (now the line is on the screen)
press ENTER, FCTN REDO (now the cursor is at the start of the line number),
remove just this number, press ENTER and
finally FCTN CLEAR to continue your programming job with another colour on the screen..
(In the next issue you will find a machine code routine, which will do the same thing without turning blue after an error message.)
1 !:i>P- 2 CALL CHAR (0
When you landed in a situation like this you will type those two lines at the start of the just loaded program. Then you type RUN and the next Tlbas error message will show you that you really left the Extended Basic mode. All you have to do now is to erase those two lines again before RUNning your program.
By the way: A LIST will show you that your program is O.K. (It won't work the other way around.)
For those of you who up to now did not buy this module, some of the extended basic statements are probably still inconceivable. To shed some light on the subject we will try to describe what this module, and it's enhanced Basic language, could mean to you.
Not in the least because of it's price I myself waited a long time before I purchased this module, TI's standard basic offered me enough possibilities to program and apart from the multiple statement lines, I myself did not know exactly what Extended Basic had in store for me.
Before reading on, readers who are still having problems with TI Basic should save this article for later since Extended Basic is a bit more complicated and this article requires mild programming knowledge.
Together with the module comes a thick manual which however is written for the old 99/4 computer. No problem for me, that's the one I started with four years ago, but 99/4(a) owners will have to keep in mind that the first computer did not support lower case and had a different layout for the function keys.
The manual therefore does not mention the lowercase character set. 99/4(A) owners should alter the text at the bottom of page 196 as follows: SHIFT A becomes FCTN(AID) and so on. The only function you wont be able to find is SHIFT V(CMD), an invalid name corrected on the 99/4(A) as FNCT(PROC'D) which happens to be the standardised ASCII name for this function.
In my opinion, one of the nicest features of this super language is the ability to program your own SUB-PROGRAMS.
Apart from the built in SUB-PROGRAMS like CALL SOUND and CALL CHAR in TI-Basic, this language has 20 additional built in SUBS. 3 of them for the Speech Synthesiser, and 4 to be used with the optional Expansion Memory.
First a useless one, CALL VERSION(X), which returns in X the version of the Module, old modules return l00, new ones return 110 in X. As far as I can see TI could have used this space better with a more useful routine by putting the version number on the label but I suspect they needed it there for their own software developments because the two versions unfortunately don't operate the same way.
(web note- As Sprites move at different speeds between versions, programmers can write their sprite using programs to operate correctly with either version automatically by using CALL VERSION)
Its beyond the scope of this article to explain this in detail but one of the main differences is that the old version is considerably slower than the llO version.
A very useful feature is: CALL CHARPAT(56,C$)::CALL CHAR(106,C$)
C$ becomes "0038443833333800" and character 106 is now a duplicate of character 56, an easy way to display a number or letter in different colours by moving them to another colorset.
In case you made a mess out of this, CALL CHARSET puts the characters 32-95 back into their original state. I'm sorry folks this routine does not work on the lowercase chars, even if you own a 99/4(a), a minor slip of the chip from TI I'm afraid.
Apart from CALL ERR all the other additional SUB-PROGRAMS deal with SPRITES. The CALL ERR can be used for debugging and experienced programmers should be able to catch input errors, correct them and keep a program running which otherwise could have stopped with FILE or INPUT ERROR, losing previously entered data and variables in the process.
With the statement ON ERROR 950 and on line 950: CALL ERR(A,B,C,D) the variable A will return the Error
Code, B=type of error, C=always 9 and D=the line where the error occurred.
Depending on these factors you may branch to a simple RETURN, or even to a statement like RETURN lOO in which case the program actually returns to line 100 and continues.
Ever lost yourself by trying figure out your program—flow after numerous GOSUBS and RETURNS ? Not to mention the problem of a forced RESEQUENCE to make room for additional lines which inevitably places your sub—routines on hard to find line numbers.
Extended Basic offers a perfect solution to this problem. You are now able to build your own SUB-PROGRAMS and CALL them by name. While the sub—routine feature, which is available in both TI—Basic and Tl—Extended basic must share the use of all variables and parameters with the main program and other subroutines to avoid conflicts, the SUB PROGRAMS may be defined with LOCAL variables and parameters, (unknown to the main program and/or other sub—programs).
Communication between the main program's variables and parameters and the sub—program's LOCAL variables and parameters is established through the use of the CALL statement and the SUB statement.
A simple example is a delay routine:
calling a subroutine
SUB W(X)::FOR A=1 TO X::NEXT A::SUBEND
By running this example, the X in the
SUB—PROGRAM gets the value of 1000 and
when the loop has been performed the
statement SUBEND acts like a RETURN
and control branches back to the main
program where you even might have used
without any conflict because A and X in this case (in the sub program) are LOCAL variables and have nothing to do with the other variables in the main program.
Should you want a shorter delay some place else in your program you may use CALL W(500) or even CALL W(X(3)), assuming X(3) contains the appropriate delay value.
Of course you may CALL a subroutine in
such a way that it returns new values
to the main program. A simple but not
so smart example is the following:
and a SUB-PROGRAM
The value of B in the main program will be A+1 after the CALL.
As I pointed out before, not so smart to do it like this. B=A+1 in the main program would be faster and shorter but with complicated calculations and or String manipulations the real power of the Sub—program capabilities can be used to the fullest.
Variables or strings that are subscripted can be
passed to SUB-PROGRAMS without a loop.
is passing the complete four dimensional X$ array in one go to a SUB (which must also receive this in a 4 dimensional string array) like SUB(J$(,,,),Y$)
The use of subscripted arrays in sub-programs may create a crash situation on some computers. On my old 99/4 I had to put a DIM statement inside the SUB to work with a local array of A(20) which I only needed there and not in the main program.
This however crashed on some of the new 4(A)'s,(not on all of the ones I tried), which evidently did not seem to like this concept.
The only solution was to DIM the array in the main program, although I had no use for it there and pass it as a parameter through the CALL. This worked on all the tested computers and took care of this strange bug.
It is possible to reserve space for 7 dimensional arrays in Extended Basic, but it gobbles up a lot of memory!
You also have an additional statement
which enables you to branch back to
your main program on a certain
condition before reaching the
IF X=10 THEN SUBEXIT
will do the job.
All SUB—PROGRAMS must end with SUBEND and be placed after the main program and may only have lines with REMarks or END following them. A SUB may not CALL itself, and return to the main program may only be through subend or subexit. Also ON ERROR may not be used to return to the main program.
The handling of error messages in Extended Basic is impressive. It's extremely easy to trace back the origin of your error. From one of this error messages I learned that the computer actually CALLS a DEF statement the same way it CALLS a Sub—program.
IF, THEN and ELSE are nice statements
if you know what you are doing.
IF A=l OR B=2 AND C=3 THEN A$=G$ ELSE A=5
is a valid one line statement!
IF A=l THEN B=4 ELSE IF X=l THEN B=3 ELSE IF Y=2 THEN X=2 ELSE IF A=2 THEN B=9 ELSE 100 (sort it out please)
Mind you these are l line statements, just imagine how many lines the last statement would take in Tl—BASIC! This way Extended basic saves you four bytes per line and works faster. Apart from the abovementioned AND OR, the module also allows you to use the logical operators XOR and NOT.
What are sprites ?
We know that characters are created by 64 dots in a 8*8 matrix. We can roughly move these characters in basic by putting them in one of the 768 available screen positions. The problem remains that the previous position has to be erased and/or restored when you move the character to another location. Something which can be rather difficult as well as time consuming if you have various coloured backgrounds which make it even more complicated to retrieve the old value and restore it while even your character's background may have to be altered.
Extended basic has an ideal solution to this problem, yes you guessed it, the SPRITES. Each standard or user defined character can be promoted to one of 28 sprites. ln order to be able to understand how this works we will have to give you some technical explanation on how the VDP chip handles the screen output.
This Video Display Processor is among other things, responsible for all the displays and does this by creating 35 flat, 'stacked' geometric planes that are sandwiched one on top of the other onto the picture tube of your TV or colour monitor.
A very short program shows you plane 35 !
l CALL SCREEN(l) 2 GOTO 2 followed by RUN.
In front of plane 35 we have plane 34, due to an oversight from Texas Instruments useless to us since they forgot to install a video input. The VDP can in fact accommodate external video allowing simultaneous on—screen mixing with computer generated graphics. Perhaps some of you are able to correct the oversight of TI and supply the non—technicals like me with a detailed account on how to fix it.
Combined with the capability of
chaining together multiple 9918a chips
(VDP's) this might give us the
potential for a visual gaming
environment that is simply mind
(web note- enthusiasts did in fact build their own computers using this facility of the vdp chip, but not using a 99/4a as a base. An important requirement is to lock the frame refresh of the computer output to the frame refresh of the external video)
Plane 33 is the backdrop plane,
slightly larger than the other 32
planes in front of it so that it forms
a rectangular rim around these on the
1 CALL CLEAR 2 CALL COLOR(1,15,15) 3 CALL SCREEN(5) 4 GOTO 4
Plane 32 is the Multi—color or Pattern plane and this one is used for the text and or fixed—graphics images so consequently you will always see the sprites in front of this plane as the VDP can place 1 sprite on each of the planes numbered 0 to 31.
Mind you, the VDP can handle this, with extended basic however we are only able to define 28 sprites. Each sprite may have one of the 15 standard colours, (the 16th is transparent) and can be set to motion without having to redefine the screen and without further program control. A sprite of a lower numbered plane (closer to the foreground) encountering another sprite on a higher numbered plane creates the illusion of passing in front of it, so with some careful planning we are able to create a realistic 3D image.
After a break all sprites disappear and wont come back with CONTINUE.
A nice feature of extended is the use of RUN "CS1" or RUN "DSK1.GAME" in a statement, you'll lose your variables by doing this but keep all the defined patterns (also below character 97) and sprites as they were. Ignore the rewind command with CS1 or you'll wind up restarting the one you just terminated.
I myself created a 80K program (consisting of 8 programs) which transfers the data I needed in the next program merely by putting the data into the character patterns I did not need for the displays. It's faster with Diskdrive(s) but also feasible with CS1, but 1et's go back to our sprites.
Where can we put a sprite ? We know we have 768 positions to display characters on. When sprites are on the screen however the VDP organises the display into a high—resolution visible pattern of 256 by 192 little boxes called "pixels". I mentioned visible because actually the sprites can be on 256 instead of 192 rows but a normal sized sprite on row 25 will of course be invisible. Each one of the 65536 (49152 visible) pixels represents a possible address for a sprite to reside at, or pass through when moving across the screen.
The shape of a regular sprite is defined by an 8 x 8 bit pattern stored in memory. Each of these 64 bits correspond to one of the 49152 screen pixels mentioned previously.
Lets make a sprite with the following
then we have placed a white O on the
same spot as the black with
If NUMBER=1 and CHAR=48 and C
OLOR=16 and DOTROW,DOTCOL=73
In this case the white sprite blots out the black character as it is in front of it. The exact location of the white sprite is determined by the upper—left hand pixel, in this case 9(rows)*8 pixels +1=73 and 9(cols)*8 pixels +1=73.
Since we set the row and column speed to zero the sprite is fixed on the spot. We did not have to use this in this example, they are optional parameters which may be left out of the call sprite statement. Some place else in the program we can activate or alter the movement with CALL MOTlON(#NUMBER,ROWSP,COLSP)
These variables must range between -128 and +127, otherwise you will get an error message and the program stops. No need for it though, they are fast enough as it is.
A positive row speed moves the sprite down, a negative up while a positive column speed moves the sprite to the right and a negative to the left. A combination of these two will move the sprite diagonally across the screen.
The color of the sprite, initially set to 16 can be altered in the program with CALL COLOR(#NUMBER,5).
Extended basic also allows you to change more then one sprite in one CALL with CALL COLOR(#1,5,#2,4,#3,6) etcetera.
CALL COLOR may be used for sprites as well as character sets but may not be combined. in one CALL. Both versions can make use of the time and byte saving extended CALL in the form of CALL COLOR(1,11,16,4,5,12).
Having set the sprite in motion it might come in handy to determine the distance between two sprites or between a fixed position on screen and a sprite. This can be done with the CALL DlSTANCE(#1,#2,D) for 2 sprites and CALL DISTANCE (#1,DOTR,DOTC,D) for one sprite and the position indicated by DOTRow,DOTColumn, and looks quit complicated.
Let us suppose that sprite #1 is still on ROW 73, COL 73 and #2 is on 81,81 the (D=DlSTANCE) variable will then be calculated as follows:
The row distance 81-73:8 raised to the power of 2=64 + the same for the distance between the columns will make D equal to 128. A child can deduct that the two sprites are not 128 pixels apart.
The exact distance can be derived with SQR(D) but you will have to calculate that yourself, Call Distance returns 128. lt works fine, as long as the objects are not to far apart.
Should D be greater then 32767 then you are in trouble because D is a real two byte (two complements) lnteger and therefore simply cannot be greater then 32767. In which case you will have to keep in mind that the value returned has no significance.
If you are still with us you will now know that 2 sprites, on different planes can never collide, instead they coincide. Coincidents between sprites or between a sprite and a fixed position can (sometimes) be detected with the CALL COINC subprogram.
Sometimes, because with speedy sprites and small tolerances the computer could be busy with another statement and not report a coincidence. Even in assembler this remains a problem.
Some coincidence calls could be:
CALL COINC(#1,#2,TOLERANCE,C)If the TOLERANCE in the first call is
24 and sprite #1's upper left hand
pixel is within 24 pixels from the
upper left hand pixel of #2 then C will
return -1. I think the other calls
Since only the upper left hand pixels are being compared and they themselves might be transparent, it is possible that a coincidence is reported for two sprites that did not visually coincide.
The background of sprites is always transparent but you may define a sprite on a higher plane and give it a different design and another colour and place it directly behind the first sprite. There is however one limitation to this, with 5 or more sprites on the same row the sprite(s) with the highest number disappear. He (or she) turns up again when this situation is remedied, so carefully planning is essential.
Now that we know how to colour the sprites and set them in motion we are busy with animation. CALL PATTERN can help us with this.
Suppose we defined a small person in
char 100 and the a similar one with
it's legs in a different position in
FOR X=100 T0 101 ::CALL PATT
in a nested loop will liven up this sprite a bit.
CALL POSITION(#1,X,Y) will return in X the dotrow and in Y the dotcolumn where our little fellow presently walks and with CALL LOCATE(#1,X+4,Y+4) our little fellow jumps half a character high and forwards.
CALL MAGNIFY(2) will blow our fellow up to twice it's normal size, the default is always MAGNIFY(1).
In this case we'd better not use the value 3.
To explain this lets review our first sprite of character 48. The use of Call Magnify(3) will show this sprite on screen as:
02 13MAGNIFY(4) will blow this up into a 32 * 32 dots sprite. Keep in mind that the character used in the CALL SPRITE or CALL PATTERN (which shows up in the upper left hand corner of the magnified sprite) should be evenly divisible by four, otherwise you wont be able to get the result you wanted.
I regret the fact that we are unable to magnify specific sprites only. All sprites are altered with the magnify statement, but we can't have everything.
Should your program encounter a Call sprite statement for a sprite which already exists, the new one will take the place of the old one.
CALL DELSPRITE(#1,#3) terminates sprites #1 and #3, with CALL DELSPRITE(ALL) you guessed it, ALL sprites are deleted.
What else have we got in extended basic? Oh, among other things PI=3.141592654 but - this we already knew how to simulate in basic with DEF PI=4*ATN(1)
That's one basic statement which will definitely issue an error message when you attempt to run it in extended, along with variables like MAX and MIN which are also extended-basic keywords, not to be used as variables.
If A=4 and B=3 then the amazing result of PRINT MAX(A,B) turns out to be 4. The result of MIN(A,B) is not to hard to guess I think?
Some of the more privileged among us, equipped with one or more Diskdrives, are able to merge a program or an often used sub-routine from DISK with the program in memory. It only works with programs or routines saved to Disks in a special way with the Merge command. A pity it does not work with cassettes.
What does work with cassettes however is SAVE CS1,PROTECTED. You'd better first save an unprotected copy, because a protected program cannot be listed, changed, saved or edited.
It used to be a nice way to keep certain procedures a secret but more and more (smart?) guys are trying to make some money by divulging how to de-protect a program, something I do not condone. The only thing I want to divulge is that you can only de- protect a program if you have the Memory Expansion.
Extended basic furthermore offers some pretty fancy PRINT versions, PRINT USING or DISPLAY USING and even DISPLAY AT.
PRINT using "###.###":A
Will print 102.50 if A=102.5 or A=102.5049
If however A=102.505 then 102.51 will be printed with this method.
Should one often have use for a certain print format then the string may be incorporated in the program as an image:
100 IMAGE "Pounds #####.##" 110 PRINT USING 100:A
R stands for Row, C for Column, Beep issues a Beep while Erase all has the equivalent of Call Clear but takes less bytes to store in memory. We also can indicate the length of the string we want to print with SIZE(X) but this is superfluous with the erase all command.
Normally when you use Display at and leave the SIZE out, the line where the string or variable is to be displayed is cleared by the Display at command.
If this is not wanted you have two alternatives, with SIZE(X) you will only clear and then print X characters no matter how long your string actually is while -X does not clear the display line but only displays a maximum of X characters.
Also handy is for example ACCEPT AT(R,C)VALIDATE(UALPHA) etc., which only accepts uppercase characters.
The size command is also usable:
ACCEPT AT(R,C)BEEP SIZE(-5):A$
In this case the negative value indicates that the input field will not be cleared and that the length of the input string may not exceed 5 characters.
This allows you to put a default string or value there which allows the user merely to press enter.
Prompts cannot be generated with Accept at so you will have to use Display at or some other way to get your message across.
With VALIDATE(DIGIT) only O to 9 may be entered while VALIDATE(NUMERIC) accepts also +,-,. and E.
If the SIZE command is not used, whether with display at or accept at, the whole line is cleared. Accept at input can not wrap around to the next line so the maximum length of string-input is 28 characters.
The DIRECT MODE uses SIZE differently. It returns the bytes free. Very useful to study how to economise on your statements.
Some seemingly minor changes can save you a lot of program space, for instance
sets three different variables to 5 and clears 3 strings in one line. Also allowed is CALL CHAR(48,A$,49,B$,53,C$)
A powerful command is A$=RPT$(G$,28); It puts 28 times the contents of G$ (a direct string expression may also be used) into A$, if this produces a string longer then 255 characters the excess is discarded and the *WARNING STRING TRUNCATED will be given.
If you are a poor programmer and don't want to be reminded so much then ON WARNING NEXT is a nice feature. It ignores your errors and branches to the next line. Apart from that it may sometimes keeps your nice neat screen from not so neat scrolling after one or more faulty inputs.
ON BREAK NEXT is handy to prevent little children from accidently breaking the game with FCTN CLEAR.
It's a nice trap to fall in if your program restarts or even runs another program. Why ? How do you break it to save it finally? I made this stupid mistake more then once so beware, save before running if ON BREAK NEXT is used.
To enable break after ON BREAK NEXT in a program is done with the ON BREAK STOP statement, the default in extended as is ON ERROR STOP. I'm afraid ON QUIT NEXT is not yet available although with the Memory Expansion and the statement CALL LOAD(-3l806,16) you wind up with a disabled FCTN Quit.
CALL PEEK is usable without the memory expansion but of very little significance since POKE is not available. To use CALL INIT, LINK and LOAD you must have the Memory Expansion otherwise an error message is all you get from the use of them.
The CALL's to be used with the SPEECH Synthesiser are CALL SAY and CALL SPGET. The manual on speech needs a lot to be desired. It did not explain why CALL SAY("TEXAS INSTRUMENTS") a valid speech string, did not work. It seems that the only way to let it speak a two words phrase is with CALL SAY("#TEXAS INSTRUMENTS#").
CALL SPGET enables you to create a String which thereafter may be used in a CALL SAY statement.
Remains to tell that extended basic allows you to place a so called TA1L END REMARK by placing a ! after your statement which may be followed by any comment you like.
! acts like REM and it does not have to be preceded with a statement.
100 ! ABC = 100 REM ABC
Most standard basic programs will run without problems in extended basic provided you did not use the characters greater then 143, which space is used by extended to control the sprite—movement, even if there are no sprites defined to be moved around.
This table goes a bit further then character 159, this explains why you have a few bytes less for your program then with standard basic.
lf you inadvertently loaded a basic game under extended basic and do not have the Memory Expansion there is a little trick to keep your program in Memory and return to basic by entering:
1 !@P— 2 CALL CHAR(OAfter RUN + Enter you will get a TI—Basic error message and after deleting line 1 and 2 you will be able to run the program.
If the memory expansion is on this will not work. You will then get the message SUBPROGRAM NOT FOUND 1N 2, and that's not a basic error message!
With !@P— you are able to shut the PRE—SCAN off (thats what the computer is doing between RUN and the actual start of the program) while !@P+ turns it on again. It's not explained in the manual but sometimes there a brochure with it which explains it fully and also points out the different meaning of certain error messages when the error occurred in a SUB PROGRAM and which also were not explained in the manual.
254n TV DEN HAku
Text written with TI—Writer and printed on Brother CE—6O with super interface.
BUGS IN EXTENDED BASIC
1 There are some tricks to create an illegal line number 0. Looks nice, but it is impossible to delete or edit this line 0. The solution is: Resequence, the old line number zero will now be the first line of the program.
2 You cannot add characters to a line whose number is a multiple of 256, if that line was reached by typing either an up arrow or a down arrow from a previous line. Those line numbers can be edited directly by typing '256' and a down arrow, but not indirectly by typing '255' and then two down arrows.
100 ACCEPT AT(3,4):A$(B—1)If in an ACCEPT statement as above an expression is used as the subscript of an array in the accept—item variable, then no value except the 'enter' key will be accepted.
4 If you get an error in the direct mode, while a program is stopped by using CLEAR (FCTN 4), a restart with CONTINUE will destroy your program. Be sure to issue an immediate command that does work (like PRINT) before you continue program execution.
BUG IN TI-BASIC
CALL KEY(1,A,B) and CALL KEY(2,A,B) do not return the value zero in the keycode (A) in the proper form.
The value returned prints as zero and works as zero in arithmetic operations, but is not equal to zero in comparisons. So in this case don't ask:
100 IF A= 0 THEN 150 but: 100 IF A+1=1 THEN 150.
This completes the first Parco magazine issue end of article
[ TI Book front page | TI Resources Page | PC99 Review | PC99 Programs ]