LnSOS BOOT 1.1 SOS.KERNEL SOS KRNLI/O ERRORFILE 'SOS.KERNEL' NOT FOUND%INVALID KERNEL FILE: xةw,@  ȱlmi8#)!)/ WAP /// SIG MENU.MAKER PROGRAM (v. 6.1) =".D1"210: Coldstart (320: Warmstart &*X=11000: TEXT SLOW-DOWN LOOP ,X.1 CHANGE DISK SUBROUTINE23œ202:2200<RFa$=" YOU MAY SELECT YOUR DISK BY V  !+%SEG.T hjK Ÿ/ (STANDARDv"!tTEXT.DUMP yH K DISKNAME.DAT#l0k5III.BSB.06IC.04u' ARTICLE18!3 ARTICLE19.!2 )BGRAF.INV( !L+,DOWNLOAD.INVq!+*MENU.MAKER  K ;+REQUEST.INVj >dLԡm#i㰼m#iЕOLԡȱfg hi !dLԡ憦  Ljmkm l y`2 Lԡ8(Je稽)ʈ@LOLUME NAME (/DISKNAME) OR DEVICE NAME (.Dx)"P12);::"80C";a$;:Zb$="CHANGING DISKS"$d=23:=0::"80C";b$;::12).n=12:=20:"MAKE A NEW MENU FOR DISK: ";N$xN$)<2110=N$ :210 I=1L(A$(I),A$))200B$( NOT FOUND.)"X=11000:X:::210Z a$="{,|,~,}; selects; back 1 level; G$:::320H: Error Routine 202:U=11:"79C";"BAD PATH ERROR (NO DISK IN DISK DRIVE OR DESIRED FILE ,2))=0"12";џ,6);:ٟ;$П,2))=>12" PM-":" AM-" 1830WW=1530 =26:=21 1600 &:WW=1:0 :SEG=1;".D1/S EG.F" SEG=1".D1/SEG.G"diskname$=3802  CATCH PASCAL TEXT FILES "JUNE":1750M$="JULY":1750M$="AUGUST":1750M$="SEPTEMBER":1750M$="OCTOBER":1750M$="NOVEMBER":1750M$="DECEMBER":1750826);"-";M$;" ";Ѡ,2));", ";"19";Р,2);" ";/П,2))=>13П,2))-12;џ,6);:1780$~240:=24:=0:"@ ..... "DATE.TIME.LINE" ....JM=Ҡ,4,2))BTM1630,1640,1650,1660,1670,1680,1690,1700,1710,1720,1730,1740^M$="JANUARY":1750hM$="FEBRUARY":1750rM$="MARCH":1750|M$="APRIL":1750M$="MAY":1750M$=B$(I),"CAT 0")1140*B$(I),"FONT 0")18504B$(I),"FOTO 0")1930>B$(I),"PASTXT 0")2070H540R\A$="RUNNING "+B$(I),16,B)f"79C";A$;:=0pB$(I),16,B) z::SEG=1".D1/SEG.T"t=+B$(I),16,B) yCT=CT+1I=1:I=2I>2=-1:I=I-2:IBOTM<30THPOS=44I=IBOTM/2)*2:=+IBOTM/2)-1:0=+IBOTM/2-.5):I=IBOTM:I/2=I/2)I=I-1 œ2120B=B$(I),16)," ")-1 B$(I),"BASIC 0")850B$(I),"TEXT 0")890 81+LCA):::: RebootN=THPOS:B$(I);XA<8A>11540bA-7640,660,690,720l:=THPOS:B$(I);v:520: 500THPOS=4:I/2=I/2)I=I-1I=IBOTM THPOS=44:I/2<>I/2)I=I+1I13000Zha$="{,|,~,}; selects; to new disk; J/2)=4:=+1:ۙ=44B$(J);:J=J+1I:1,180,22:2,280,21:2,2380,23:8A$(1000),B$(1000),C%(511),C$(20),name$(20):=10:=0UCA=128:LCA=UCA+32CT=15 IF PREFIX$= PREFIX$+MID$(B$(I),112405l=ơ):: Routine to back up one directory level.a$=С,l-1) s=a$)a$=a$,s-1)a$,1)="/"5060:s=s-1 5030=a$240( MENU.MAKER 6.10 * Thanks to C.M.Davidson for his help!ARTICLE19v.' '.BIG.ARTICLE.19E5(BUG.FONT1*8*EDIT.SHAPE .1:)FAST.MOVE 60FONTLOAD.SUB 1)FREE.FIRE }    `OLIHEDCB?<;8541.+*x  `"hhhhhhhh    HH`XVTRPN.GRAFIX jj# \\JHFD=;9210-,+*)!   v Q )``.`5`=`C`E` `BGRAF (C) APPLE 1980j @@@@ @``` kLK``9(89:9g:h:h L89:mm95:6:6hg gh h 99 O S   L `ee m`iɂ`0`hIhJh\h] wh]h^ w\\ ]] ]L ]L\A \A JHIH`i8\i]i\`\]`K`M %b&*L+ 16>:)    kL !"#$efgGA3/1.01/LINr GRAFIXMO ARTICLE18v' '*ARTICLE.18&@e|79C";"PRESS ANY KEY TO HALT LISTING"::202 1020#2,B$(I),16,B)ž#242:::1160Z=1#2;A$:"78A";A$Z=Z+1:Z>1842:::Z=1980*:=23:=0::"79C";"CONTINUE...?":1C$:C$<>"Y"C$<>"y"C$<>"N"C$<>"n"10 MENU.MAKER TEXT MODULESEG=0"MENU.MAKER"890&*X=11000: TEXT SLOW-DOWN LOOP ,X.1,180,22:2,280,21:2,2380,23:z:A$="LISTING "+B$(I),16,B)$=01:=0::"80C";A$;::12)>=23:=0::"1HIRES.CRAWL {0(MOVE.BUG4T-MOVE.BY.THREE 3*MOVE.HEADS 5+MOVE.SINGLE 5*NEXT.SHAPE 2M$LJFE>987410/-   `+(%" Bhhh h h h hh hhhhhh  HH`ZXVTRPNLJHFDB@<;85431hhhh   HH`420.-&#  Phhhhhhhhhh  HH`DB@><:86421.+*)'jhhhhhhhh    X XSOSWRITESWRITERWBUF  RETADDR PLINITCHK sITCHK VIEWPORT VIEWPORTWBUFLEN }UFLEN SOSWRITESWRITERWBUF  xplhd`\XUFLEN SOSWRITESWRITERWBUF ~zvrRETADDR $ INITCHK ITCHK XFROPTIO XFROPTIORANGECHKNGECHKWBUFLEN UFLEN #ITCHK WBUFLEN DUFLEN SOSWRITEGSWRITERWBUF ?:72-(SYSFONT SYSFONT RETADDR njDRAWIMAG DRAWIMAGINITCHK ITCHK WBUFLEN RETADDR INITCHK ITCHK RANGECHKECHKWBUFLEN UFLEN SOSWRITESWRITERWBUF  NEWFONT NEWFONT INITCHK =+SOSWRITE@.!RWBUF  83& INITCHK uITCHK GRAFIXON GRAFIXONWBUFLEN UFLEN SOSWRITESWRITERWBUF zBUF GPGSREQDLGRAFIXMO GRAFIXMORBUFLEN 9RANGECHKwWBUFLEN ASOSWRITERWBUF \SOSREAD GBASADR TSOSSMARK$INITCHK ITCHK INITGRAF INITGRAFWBUFLEN RETADDR ISOSDSTATGSCB kSOSOPEN INITCHK READPARM5CREFNUM DWBUFADR ?BMOVCHK RBUFADR 7WRITEPAR=SREFNUM FRREFNUM 6WREFNUM >INITFLG KSOSCLOSEhhhhhh HHHH`&$<D^Z FpHx  )) y xHHHJJiH 詏 鮀 `}wqnkjba_\[ZYXWVURQ$hhhhhh HH H)HHH`20+*)Hhhhhhh HHHH`&$< 詏 )x `a^]NMJGF>=<10/.+* )) y xHHHJJiH 詏 鮀hhhh  HH`420.,*)&#"! Rhhhhhh    HH`DB@><:983.+('&$h J)` `!0 nljhfdcbQNMLJFEDCBA<;6hhhhhh  HH`420.,*)&#"! Rhhhhhh    HH`DB@><:983.+('&$hhh-&#  P  `"hhhhhh  HH`420.,*)&#"! Rhhhhhh  B B HH`yyP`GB HH`)r` @A>~|zxvtslgbWTSRPMED=hhhh   HH`420.-&#  Phhhh   HH`420.TRETADDR  SETCTAB SETCTAB  INITCHK ITCHK RANGECHKHKWBUFLEN UFLEN SOSWRITESWRITERWBUF  'RETADDR tpINITCHK ITCHK PENCOLOR PENCOLOR RANGECHKNGECHKWBUFLEN UFLEN SOSWRITESWRITERWBUF |x FILLCOLO FILLCOLO s going to become pretty important this time, as we continue our discussions of graphics by developing an arcade "Shoot-em-up" called "Bug-Mania". In the process, we'll explore an area of graphics that most people overlook, the 40 column color-on-color te%'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdd Last month's article was a lengthy tome on editing character fonts and shapes, delivered under the promise that it could be used to create "fun stuff". What else excuses the need to type in such a long program? That program, or something equivalent, iE T H E T H I R D B A S I C by Taylor Pohlman Exploring Business Basic, Part 18 Looking Through a Glass BackwarWBUFADR   ADR GSAVE GSAVE WREFNUM F  M GPGSREQD5 GSREQDSOSCLOSE> SCLOSEWBUFLEN 8  LEN SOSWRITE; SWRITERWBUF C F INITCHK  ITCHK BMOVCHK  OVCHK INITFLG  ITFLG RWBUF  F SOSDSTAT" SDSTATGSCB % CB INITCHK  ITCHK CREFNUM  EFNUM  T P SOSDSTATj SDSTATGSCB LINEREL LINEREL INITCHK g ITCHK WBUFLEN  UFLEN SOSWRITE SWRITERWBUF } d ` \ X RELEASE RELEASE  RETADDR % ! INITCHK  ITCHK LINETO LINETO WBUFLEN  UFLEN SOSWRITE SWRITERWBUF     CALCABS x q ABS RETADDR CALCABS  ABS RETADDR  SOSDSTAT SDSTATGSCB INITCHK  ITCHK DOTREL DOTREL WBUFLEN  UFLEN SOSWRITE SWRITERWBUF SWRITERWBUF  RETADDR c _ < 8 INITCHK O ITCHK WBUFLEN Y UFLEN SOSWRITE\ SWRITERWBUF T L H D @ DOTAT DOTAT RWBUF ZRNJFCALCABS BRETADDR SOSDSTATSDSTATGSCB  MOVEREL MOVEREL INITCHK ITCHK WBUFLEN UFLEN SOSWRITEWBUFLEN !UFLEN SOSWRITE$SWRITERWBUF BUF RETADDR ieB>INITCHK UITCHK MOVETO MOVETO  WBUFLEN _UFLEN SOSWRITEbSWRITERETADDR INITCHK ITCHK RANGECHKNGECHKWBUFLEN UFLEN SOSWRITESWRITERWBUF  INITCHK ITCHK FILLPORT FILLPORT xt mode. Now that we can create special character shapes and load them into the standard character set, a class of graphics known as "character set animation" is not only possible, but highly practical and rewarding. Most people don't realize it, but the capabilities of the Apple ][ "DOS Toolkit" Animatrix package are supplied as standard in the Apple ///, and work at hardware speeds! However, to make all this neat stuff really work for you, you need a character set editor, such as the one discussed last display of the string "m$". For each value of "i", the string is split into two parts, on the boundary between the beginning and end of the string. When i=0, then the result is "MID$(m$,41,0);MID$(m$,1,40)". This is the combination of the "null" stringd the background color to yellow (13). The HOME command sets the whole screen to the background color, and then the routine to scroll m$ begins in line 80. It is important to go through the routine at lines 80 through 110 to see how this accomplishes the after character". You should check out the Standard Device Drivers Manual for more details on the cursor options of the Console Driver. Line 40 puts the screen into 40 column color text mode, and lines 50 and 60 set foreground color to dark green (4) ann to display the strings on the screen into "start$", using the cursor positioning command of the console driver. The code shown will set a starting location at column 0, row 10. Line 30 sets the cursor movement options to disable everything but "advance NEXT i 120 GOTO 80 130 TEXT:HOME 140 END Line 10 defines a 40 character string, exactly as wide as the screen mode we will use. Be sure when you type it in that the result is exactly 40 characters in length. Line 20 puts a starting locatio0)+CHR$(10) 30 PRINT CHR$(21);"1"; 40 PRINT CHR$(16);CHR$(1); 50 PRINT CHR$(19);CHR$(4); 60 PRINT CHR$(20);CHR$(13); 70 HOME 80 FOR i=0 TO 39 90 PRINT start$;MID$(m$,41-i,i);MID$(m$,1,40-i) 100 GET a$:IF ASC(a$)=27 THEN 130 110s horizontally across the text screen. We'll start with using groups of asterisks (realizing that we could redefine them to almost any shape). The program looks like this: 10 m$=" ** **** ** **** *** * **** ** ***" 20 start$=CHR$(26)+CHR$(takes a lot of work to move objects around on the hi-res screen. Careful use of the Apple /// built-in routines, and the user-definable character set will allow us to do much the same thing in Basic! To begin, let's look at a routine which scrolls objecthat each take as little time as possible, in order to make the whole game smooth and fast. Normally on the Apple ][ and other similar systems, this is accomplished with assembly language routines, which execute fast enough to make up for the fact that it han one activity going on the screen simultaneously. This means that the targets should move along with the weapons, and firing at objects should not bring everything to a halt. Since each of these activities takes some processing time, it is important tt it can be used by other system proceedures. This allows you to edit a font and then configure it with SCP, etc. Congratulations, Foxware! Doing the Sideways Scroll One of the critical elements of any "shoot-em-up" game is the ability to keep more tupshift, and, most interesting to last month's article, the ability to change file types. Sepcifically, the editor from the last article has been modified with this routine to automatically change the edited font file to the system filetype "FONT", so that from Foxware Products of Salt Lake City, Utah. I highly recommend that you get a copy of this product, which they call "BASIC Extension". In addition to routines to manipulate and search arrays, it contains useful functions like Reset lockout, reboot, time. If you don't have last month's article, you can still use the programs, but they won't make much sense, and they certainly won't be pretty. Since last month's article was written, a set of Business Basic Invokable Modules has appeared on the marke, together with the entire string (1,40). For i=1, the combination is "MID$(m$,40,1);MID$(m$,1,39)", that is, the last character of the string, coupled with the first 39 characters. The end of the sequence, i=39, is equivalent to "MID$(m$,2,39);MID$(m$,1,1)" and finishes rotating the string around to start again. The GET statement in line 100 allows the display to freeze after each step, so you can see exactly how this works. To see the effect of the scrolling, simply hold down any key (except ESCAPE) aisplayed) and make sure the characters are no more than eight dots high. Save the character set using the "font" option, with any name you like. If you have a way to change the resulting file to the official "FONT" type (via the invokable module discusserapidly on the screen as characters. Since the shapes will be displayed as a character font, remember the rules for system character fonts: Use the first seven dot positions only ( the eighth is used for "flash/no flash" in inverse mode and will not be det in 23-25 are designed to make the mouth open and close, the legs move, and the tail wag! This is the origin of the concept "character set animation", since the animation of an object is accomplished by displaying several related versions of the object etter looking "bug" than this, so play around with the editor until you are satisfied. Watch the "280 X 192" window on the editor to get an idea of how your creature will look in 40 column mode. Notice also that the changes from the set in 20-22 to the s |X|X|X|X|X|X|X| |X|X|X|X|X|X|_| |_|X|_|_|_|_|_| | | |X|_| |X|_| |_|_|X|X|X|_|_| |_|_|_|_|_|_|_| |_|X|_|_|X|_|_| |_|_|_|_|_|_|_| |_|_|_|_|_|_|_| |_|X|_|_|X|_|_| |_|_|_|_|_|_|_| Creepy, right? Actually, you can probably create a b____ _______________ |_|_|_|_|_|_|_| | | |X|X|X| |_| |_| |X|X|X| |_| |_|_|_| | |_| | |X|X|X|X|X|X| | | |X|X|X| |X| | | |_| |X|X| |X| |X|X|X| |X| |X| |X|X| |X|X|X|X| |X|_|X|_|_|X|X| |X|X|X|X|X|X|X| |X|X| | | |X|X| |X| |X|_|_|_|X| |_|_|_| | |_|_|X|X|_|_|_| |_|_|X|_|_|X|_| |_|_|X| | | |X| |_|_|_|_|_|_|_| |_|_|X| |_|X| | |_|_|_|X|X|X|_| |_|_|_|_|_|_|_| |_|_|X|X|_|X|X| |_|_|_|_|_|_|_| 23 (151) 24 (152) 25 (153) _______________ ___________|_|_|_|_|_| | | |X|X|X| |_| |_| |X|X|X| |_| |_|_| |_|_|_| | |X|X|X|X|X|X| | | |X|X|X| |X| | |_| |X|_|_| |X| |X|X| |X| |X|X| |X|X|X|X|X|X|X| |_|X|_|_| |X|X| |X|X|X|X|X|X|X| |X|X|_|_|_|X|_| |_|X| | |X|_|X| |X|X|X|X|X|X|X| |X|X| acter numbers without changing their definition, but the "creatures" will not make any sense. In any case, here's a suggestion for the "bug" set: 20 (148) 21 (149) 22 (150) _______________ _______________ _______________ |_|_mal 148 through 153. This prevents the animation characters from interfering with any other normal character printing we may have to do. If you haven't seen the last issue, and don't have access to a character set editor, you may simply use the same charle animation without getting too complicated. Arbitrarily the characters from decimal 20 through 25 are picked to be redefined. These normally are "Control characters" and are not displayed unless referenced by their character number + 128, that is, decis and creatures of your own to populate your game world. "Oh Scroll a Mio" We'll start by defining the characters which will bring our creature to life. To make things interesting, we'll use two versions of the "bug", so that we can produce some simp cut out line 100 completely. Those asterisks will really fly! Line 130 is important since it snaps you back to 80 column reality with the cursor options restored. Well, so much for the simple stuff. Now it's time to add the options to create objectnd the pattern will scroll rapidly to the right. Holding down the "closed-Apple" key in combination with the other key will cause faster scrolling (since the characters are presented to GET faster). If you want to see how fast this thing will really run,d earlier, or the Pascal System Filer), do so now. This will save some hassles later. Can't Tell One Bug from Another Without a Program Now for a program which will display these characters on the screen and accomplish the animation! We'll use the scroll technique from the last program, together with character strings made up of our new character font. 10 DIM a%(511),char$(3) 15 q$=CHR$(34):esc$=CHR$(27):slen=40 20 array$="a%":char$(0)=" " 25 text40$=CHR$(16)+CHR$(0) 30 b$=" ":b2$=" slen-i-1) 130 GET z$:IF z$=esc$ THEN 200 135 NEXT i 140 GOTO 110 Lines 110-140 are the main scrolling loop. As you can see, it looks basicly (heh-heh) like the lines in the last program, with several important differences. Since we have twoicle and cannot change the saved file type to "FONT". And now, on with the show... 110 FOR i=0 TO 39 STEP 2 115 PRINT tc$;MID$(m$,slen+1-i,i);MID$(m$,1,slen-i) 120 GET z$:IF z$=esc$ THEN 200 125 PRINT tc$;MID$(n$,slen-i,i+1);MID$(n$,1,hanges are: 35 INVOKE "/BASIC/download.inv","/BASIC/request.inv" 90 OPEN#1,name$:PERFORM filread(%1,@array$,%1024,@ret%) 92 IF ret%<>1024 THEN PRINT "Not a font file":GOTO 40 Remember, make these changes if you use the font editor from the last artused the font editor from the last issue, or some other font editing technique, and cannot change the saved file as an "official" system type "FONT" (as shown by the CATalog listing), you must make some modifications to what's been described so far. The chrough 105 get the font specified earlier, set up the screen mode, load the font into the standard character set, and turn off all screen options except advance, allowing us to write to the screen without interference from scrolling, etc. NOTE: If you string to the next. This would allow bugs like caterpillars, which move by shortening and lengthening their bodies! 90 PERFORM getfont(@name$,@array$) 95 PRINT text40$;:HOME 100 PERFORM loadfont(@array$) 105 PRINT CHR$(21);"1"; Lines 90 trray. Then lines 75-85 do the same thing for a second string, "n$" which will contain the shifted versions of our bugs. Although we kept the bug structures the same in m$ and n$, nothing prevents us from redefining even the length of the shapes from one he periods (".") in between the numbers are simply placeholders, which have a value of 0. Remember that we assigned a space to "char$(0)". Line 70 reads the values in "m$", one character at a time, and substitutes the appropriate value from the "char$" ao the pieces of our first "bug". Then the "m$" string in line 65 tells what piece to put in what position. This allows us to create bugs which consist of a head only, a head and a tail, a head, body and tail, or any combination our imagination permits. T0:SUB$(n$,i,1)=char$(VAL(MID$(n$,i,1))):NEXT i Lines 60 through 85 look complicated, but they are simply the instructions on how to set up the strings to be scrolled across the screen. First, line 60 creates values in the "char$" array which correspond t(150) 65 m$=".23...123.1223..13.123.3.23...123.1223.." 70 FOR i=1 TO 40:SUB$(m$,i,1)=char$(VAL(MID$(m$,i,1))):NEXT i 75 char$(1)=CHR$(151):char$(2)=CHR$(152):char$(3)=CHR$(153) 80 n$=".23...123.1223..13.123.3.23...123.1223.." 85 FOR i=1 TO 4s to turn on 40 column black and white mode (mode 0), and "tc$" contains the cursor addressing command to position the cursor to row 0, line "l", using the line number that was input on line 50. 60 char$(1)=CHR$(148):char$(2)=CHR$(149):char$(3)=CHR$. Note that the array "a%" is dimensioned to hold an entire character set which "Download.inv" will load off disk. You'll have to change the pathname of "Download.inv" to be correct on your own system. In addition, "text40$" contains the console command":b3$=" " 35 INVOKE"/BASIC/download.inv" 40 INPUT"Name of font file: ";flname$ 45 name$=q$+flname$+q$ 50 INPUT"Line number to crawl on: ";l 55 tc$=CHR$(26)+CHR$(0)+CHR$(l) The lines above do the initalization of several arrays and values strings to print, we cut the number of interations in half, and adjust the subscripts in each MID$ function to print successive strings in the sequence. We still use the GET statement to pause between each change, but now it permits us to see the animation as it progresses. Again, holding down any key will permit smooth scrolling and motion as the little creatures open and shut their mouths, move their legs and wag their tails. 200 PRINT CHR$(21);"="; 205 PRINT CHR$(22);CHR$(14); 210 TEXT:HO2$=l4$+l4$+l4$ 65 e$=" "+bu$:e4$=e$+e$+e$+e$:e12$=e4$+e4$+e4$ 70 lin$(0)=na$+l12$+l4$+"*":lin$(1)=na$+l12$:lin$(2)=na$+l12$+l$+l$: lin$(3)=lin$(1) 75 blk$(0)=e12$+e4$+av$:blk$(1)=e12$+av$:blk$(2)=e12$+e$+e$+av$: blk$(3)=blk$(1) 80 jf you have a black and white (or black and green), the result will be shades of gray (or green). The strings "tc$", "t2$", "t3$", "t5$" and "t7$" will be used later on to position various other strings on the screen. 60 l$="|"+bu$:l4$=l$+l$+l$+l$:l1(8)+CHR$(23):t7$=t$+CHR$(35)+CHR$(23) Lines 25-55 set up more constants for the program, especially the values for various foreground-background color combinations. This time we'll be using the 40 column color-on-color mode for more visual excitement. ICHR$(9):green$=CHR$(12):mblue$=CHR$(6):white$=CHR$(15) 40 og$=fg$+orange$+bg$+green$:bw$=fg$+mblue$+bg$+white$ 45 text40$=CHR$(16)+CHR$(1):t$=CHR$(26):t1$=t$+CHR$(0):bu$=CHR$(11) 50 tc$=t1$+CHR$(4):t2$=t1$+CHR$(6):t3$=t1$+CHR$(8) 55 t5$=t$+CHR$ 23 better, you should read the section of the Standard Device Drivers Manual on the programs. 25 q$=CHR$(34):array$="a%":b$=" ":b2$=" ":b3$=" ":char$(0)=" " 30 fg$=CHR$(19):bg$=CHR$(20):slen=40:na$=CHR$(21)+"0":av$=CHR$(21)+"1" 35 orange$=$(4)+ep$:beep$(1)=bp$+CHR$(8)+CHR$(6)+ep$ 23 beep$(2)=bp$+CHR$(18)+CHR$(5)+ep$:beep$(3)=bp$+CHR$(197)+CHR$(6)+ep$ These lines set up the arrays to be used and create the tones which will indicate different kinds of hits. To understand lines 20 through 5 DIM a%(511),dq$(39),eq$(39),fq$(39),lin$(3),blk$(3),j(255),pnts(4) 10 DIM m(40),char$(3),beep$(3) 15 INVOKE".d3/download.inv" 17 OPEN#1,".audio" 20 bell$=CHR$(7):bp$=CHR$(128)+CHR$(63):ep$=CHR$(1)+CHR$(0) 22 beep$(0)=bp$+CHR$(7)+CHReatures and the obstacles will be moving using the techniques from the previous program. In addition, every good game needs some sound effects. We'll use the ".audio" driver to make some tones to liven up the game. With that said, lets look at the game:res and make them targets in a shooting gallery ("Oh, no" you cry, "not our poor creatures!"). To be a little fairer, we'll put some moving obstacles between the shooter and the creatures, and deduct points when the bullets hit the obstacles. Both the crmo disk was done somewhat in this way. Business BASIC Gets a Little Gamey By now we've covered all the essentials necessary for you to quickly follow the discussion of the "arcade" type game below. Basically, we're going to take our scrolling creatuthe creepy creatures should crawl across the screen at your command. Its fun to elaborate on this program, by editing more complex characters, or creating more versions of them to get smoother animation. In fact, the "Running Horse" demo on the System Ded clears it to blanks, and then lines 215 to 225 restore the standard character set and turn the screen back on. You should change the pathname to the name of the character set you normally use. Well, that wraps up the example program. When you run it, back to normal (line 200), line 205 shuts off the screen while the cleanup is being done. The CHR$(22) is there to syncronize shutting off the screen with vertical blanking, to avoid funny flashes on the screen. Line 210 restores the 80 column screen anME 215 name$=q$+"/BASIC/standard"+q$ 220 PERFORM getfont(@name$,@array$):PERFORM loadfont(@array$) 225 PRINT CHR$(15); 230 END Lines 200-230 perform cleanup, but in this case there's more to clean up than before. After setting console options(32)=1:j(8)=2:j(21)=3:j(13)=4:j(141)=5:j(27)=6 Lines 60-80 set up additional variables and strings needed for the program. In particular, the "lin$" array contains various versions of the characters used to represent firing of a shot at the creatures. It is made up of sets of vertical bars (the "|" character) combined with the vertical tab character contained in the "bu$" string. Vertical tab is used because the shot is fired from the bottom of the screen toward the top. Each string in the array is pre a creature. "T4$" contains the position of the gunner, and "t6$" is the position from which the firing of "lin$" takes place. Now we're ready to look at the additional setup subroutines. The first, at line 700, loads the font of our choice. It looks vs us to up the points values in each round, or start over, by going to lines 150, 160 or 170. The values in the "pnts" array are to be subtracted for hitting various combinations of barriers, and "hit" is a multiplier for scoring a hit on various parts ofll contain the horizontal position of the gunner at all times. Points scored and number of hits are also set to zero. Line 160 clears the point value array, and sets the value of a hit to zero, and line 170 increments them by a standard amount. This allow5 GOSUB 600:REM set up screen Lines 140-185 do the last of the setup and perpare to play the game (at last! at last!). We'll discuss the subroutines in a minute. First, note that line 150 defines the initial position of the gunner, "hr=20". "Hr" wi0 hr=20:points=0:hits=0 160 pnts(1)=0:pnts(2)=0:pnts(3)=0:hit=0 170 pnts(1)=pnts(1)+4:pnts(2)=pnts(2)+2:pnts(3)=pnts(3)+6:hit=hit+5 175 t4$=CHR$(26)+CHR$(hr-2)+CHR$(21):t6$=CHR$(26)+CHR$(hr-1)+CHR$(20) 180 GOSUB 800:REM load up the bugs 18 them both successively, along with one occurance of "fq$" the result will be that the first set of barriers will appear to scroll twice as fast as the first. Try this out in a simpler program if it's hard to follow. 140 GOSUB 700:REM get font 15le them. Line 110 handles this in a straight-forward way, but lines 100 and 105 create "dq$" and "eq$" in a more confusing way. Basically, the process is this: "dq$" and "eq$" contain every other occurance of "e$", the string to be scrolled. By printinghe MID$ functions when the string is actually printed on the screen, they are done in this loop and the results stored in string arrays to be printed later. Since these strings won't change, this becomes a more efficient, and therefore faster, way to hand(f$,x1+1,slen-x1)+MID$(f$,1,x1):NEXT Lines 90 through 110 set up the scrolling barriers mentioned above. "E$" and "f$" can be any arrangement you like, but be sure to make them exactly 40 characters long. Notice that instead of waiting and performing t" 100 FOR x1=0 TO 39 STEP 2: dq$(x1/2)=MID$(e$,slen+1-x1,x1)+MID$(e$,1,slen-x1): eq$(x1/2)=MID$(e$,slen-x1,x1+1)+MID$(e$,1,slen-x1-1):NEXT 105 FOR x1=20 TO 39:j=x1-20:dq$(x1)=dq$(j):eq$(x1)=eq$(j):NEXT 110 FOR x1=0 TO 39:fq$(x1)=MID$ce of "blk$" to turn advance back on. Line 80 sets up the values for the routine that decodes keystrokes and decides what to do. More on that later. 90 e$="== == === == === = ==" 95 f$=" === == = == === == ===ra characters, you could make the line and the burst different colors. Line 75 defines "blk$", which erases a shot right after it's fired. This gives the impression of a quick blast from the gunner. Notice that "av$" is added to the end of each occurran. Anything that reduces the number of characters printed on the screen speeds up the action. Notice also that "lin$(0)" has an asterisk as the last character. This represents a burst as the shot goes through the barrier and explodes. By adding some extfixed by the "na$" string, containing the screen control codes to turn off "character advance". This comes in handy in printing vertically, since it is only necessary to go up after printing, not back up and then go up as would be true if "advance" was onery similar to the routine from last time: 700 INPUT"Name of font file: ";flname$ 705 name$=q$+flname$+q$ 710 PERFORM getfont(@name$,@array$) 715 RETURN Again, if you can't change your edited font files to type FONT, make the changes in this routine which were suggested in the last program. The routine at line 800 is used to set up the "bug" character strings. It is derived from the last program and looks like this: 800 temp$=".12...123.1234..12.123.1.12...123.1234.." 805 char$(1)=CHRif the top barrier ("eq$") is closed. If both barriers are closed, then "g" is 3. This will affect scoring, as we'll see later. Note that we really only need to calculate "g" when a shot is taken, but we've got time to waste in this loop, and we will neression, you will find that "g" is 0 if both "fq$" and "eq$" are blank at the current location of "hr" (the gunner's position). This would indicate that the barriers are open at that spot. "G" is equal to 1 if the bottom barrier ("fq$") is closed, and 2 "i" is odd, 1 if "i" is even. This allows us to choose which version of the creatures we will display on this round. Then "g" is calculated. "G" is a number which indicated what the state of the barriers is. When you analyse the complicated logical expo 300 when a key is pressed. In the meantime, line 200 is continously executed. This is a complicated routine, so let's look at each part of the line. First, the scrolling loop is set up as before. Then a value for "c" is calculated. "C" will be 0 if 300 200 FOR i=0 TO 39:c=(i/2=INT(i/2)): g=(MID$(fq$(i),hr,1)<>b$)+(MID$(eq$(i),hr,1)<>b$)*2: PRINT tc$;MID$(m$(c),slen+1-i,i);MID$(m$(c),1,slen-i); t2$;dq$(i);t3$;fq$(i);t2$;eq$(i):NEXT:GOTO 200 Line 190 sets up an "ON KBD" jump tt to have scrolling and motion taking place all at once. As we have seen in previous articles, the best way to tackle that is the "ON KBD" capability, where the Apple /// can be doing something but still respond when a key is pressed. 190 ON KBD GOTO an edit the "X" character to any shape you like. Then the screen is turned back on in line 665 and the game is ready to play. Getting Underway in Bugland All the proceeding gets us ready for the actual playing proceedures. To make the game fun, we wan is then loaded as the standard character set, and various parts of the screen are filled in using orange on green color text. Then line 660 turns blue on white mode back on, and an "X" is printed at the current location of the gunner. If you want, you cbw$;t4$;" X "; 665 PRINT CHR$(15); 670 RETURN First the screen is turned off, so the setup can be completed quickly and without being seen. Then 40 column color mode (blue on white) is chosen and the screen is cleared to white (line 605). The fontvance 630 PRINT og$;:PRINT USING"40c";b$ 635 PRINT USING"40c";"Bug-Mania":PRINT USING"40c";b$ 645 VPOS=23:PRINT USING"40c";b$:PRINT USING"40c";b$ 650 PRINT" Score:";:HPOS=31:PRINT"Hits:"; 655 PRINT t5$;points;" ";t7$;hits; 660 PRINT keeps going. We'll see exactly how this is done later. The last setup routine creates the screen and playing area. 600 PRINT CHR$(14); 605 PRINT text40$;bw$;:HOME 610 PERFORM loadfont(@array$) 615 PRINT av$;:REM turn everything off but adcreate the array "m", which is used to score hits and quickly decide how long an individual creature is. The game uses the principle that if you hit a creature, you destroy everything from the point of impact back, but whatever's left in front of the hit .123.1223..13.123.3.23...123.1223.." 850 FOR i=1 TO 40:SUB$(m$(1),i,1)=char$(VAL(MID$(m$(1),i,1))):NEXT i 855 FOR i=1 TO 40:m(i)=VAL(MID$(temp$,i,1)):NEXT i 860 RETURN The only real difference here is in line 800 and 855. These lines combine to $(148):char$(2)=CHR$(149):char$(3)=CHR$(150) 810 m$(0)=".23...123.1223..13.123.3.23...123.1223.." 820 FOR i=1 TO 40:SUB$(m$(0),i,1)=char$(VAL(MID$(m$(0),i,1))):NEXT i 830 char$(1)=CHR$(151):char$(2)=CHR$(152):char$(3)=CHR$(153) 840 m$(1)=".23..ed every millisecond when a shot is actually fired to avoid slowing down the game. Next the appropriate version of the creature string is printed, and then the barrier strings are printed. Notice that printing "dq$", "fq$" and "eq$" in that order has the effect of scrolling the top barrier twice as fast as the creatures, in the same direction, and scrolling the bottom barrier at the same speed, except, because of the way "fq$" was created, it appears to scroll backwards. After scrolling through the entir not zero, then a machine "bell" is sounded (note that a "BELL" character sounds without slowing down the program like a tone does). Line 425 then backs up along the string adding up points and zeroing out the "m" array. Line 430 blanks out the appropriaIf g=0, then the bullet made it through the barriers and a check is made in line 415 and 420 to see if anything was hit. If the "m" array contains 0 at that point, then the shot was a miss, the appropriate tone is sounded, and a return is made. If "m" is "g" is checked to see if the bullet struck a barrier. If so, the appropriate number of points is deducted, and a tone is sounded with pitch corresponding to which barrier was struck. Then a jump is done to 450 to print the new point values and return. see if the keystroke happened during the loop exit and restart time. If so, a return is made with no action taken. This rarely happens, but must be provided for. Next, the gun is fired, by printing "lin$" and "blk$" at the current gunner location. Thenj+1,ch-j)=" ":SUB$(m$(1),j+1,ch-j)=" ":hits=hits+1 450 PRINT og$;t5$;points;" ";t7$;hits;bw$ 460 ON KBD GOTO 300 470 RETURN Lines 400-470 are the firing subroutine, and this is where all the action takes place. First, a check is made to points=points-pnts(g):PRINT#1;beep$(g):GOTO 450 415 ch=slen*(i>hr)+hr-i 420 IF NOT m(ch) THEN PRINT#1;beep$(g):GOTO 450:ELSE:PRINT bell$; 425 FOR j=ch TO ch-m(ch)+1 STEP-1:IF m(j) THEN points=points+m(j)*hit: m(j)=0:NEXT 430 SUB$(m$(0),es the previous image of the gunner in the old position, no matter which way he moved. Then the ON KBD statement is re-activated, and the routine returns the the loop at 200. 400 IF i=40 THEN 460 405 PRINT t6$;lin$(g);t6$;blk$(g) 410 IF g THENt edge. You could reduce these values to restrict the gunner to a certain section of the screen. Line 350 changes the values of "t4$" and "t6$" to represent the new value of "hr" and reprints the gunner with spaces on each side. Printing the spaces eras0 hr=hr-(hr>2):GOTO 350 340 hr=hr+(hr<39) 350 SUB$(t4$,2,1)=CHR$(hr-2):SUB$(t6$,2,1)=CHR$(hr-1):PRINT t4$;" X " 360 ON KBD GOTO 300 370 RETURN This simply resets the value of "hr" after being sure that "hr" is not already at the left or righle" RETURN (ASCII 141) restarts with doubled point and penalty values. Finally, an Escape (ASCII 27) jumps to 500 and ends the game. Looking at these individual routines will end our discussion of this game and get us down to playing it. Let's go: 33f z=32 (space bar). This is the firing signal. Lines 330 and 340 process right and left arrow keys (ASCII 8 and 21), respectively, which are used to move the gunner around. A RETURN (ASCII 13) jumps back to line 150 to begin a new game, and an "Open-Appis happening. This technique of branching is very wasteful of space (the "j" array takes up 1K of memory), but is extremely fast, which is what we need in processing these keystrokes. Cross referencing line 80 tells us that the jump to line 400 happens i turn off the keyboard interrupt, and assign "z" the ASCII value of the character that was typed. This is used in line 305 to determine which processing routine to jump to. Check the definition of the "j" array in line 80 for more information about what e "m$" array, the routine goes back and starts over endlessly, until a key is pressed. Which brings us the the "ON KBD" routine at line 300: 300 OFF KBD:z= KBD 305 ON j(z) GOTO 400,330,340,150,170,500 310 ON KBD GOTO 300 315 RETURN First wete parts of the "m$" strings and bumps the hit count. With the strings changed, the next printing of "m$" will erase the bug from the point of the hit backwards. Line 450 then prints the new score and play resumes. Notice that the major work of the game is done in this routine. Anything which makes this routine simpler or faster has the effect of speeding up play, and making the game more fun. This finally brings us to the last routine, which ends the game: 500 PRINT CHR$(21);"=" 505 PRINT CHR$YLOC  SDSTATGSCB  INITCHK  ITCHK XLOC XLOC RETADDR     SOSDSTAT SDSTATGSCB   INITCHK  ITCHK YLOC  ASADR SOSSMARK SSMARKRETADDR  z v INITCHK  ITCHK XYCOLOR XYCOLOR RWBUF  F SOSREAD  SREAD RETADDR  SOSDSTATGPGSREQD GSREQDSOSCLOSE SCLOSEGRAFIXMO AFIXMOGLOAD GLOAD RBUFLEN  N RWBUF    SOSREAD  EAD GBASADR GBASADR ( ASADR SOSDSTAT~ SDSTATGSCB  INITCHK { ITCHK CREFNUM  EFNUM RBUFADR  ADR SREFNUM  EFNUM RREFNUM  M n "text" mode, can be implemented on the high-resolution graphics screen. Until then, blaze away! emented on the high-resolution graphics screen. Until then, blaze away! d one important capability to this game, that of smooth scrolling with the character download capability. That's the real way the "Horse Demo" works. In addition, we'll start our exploration of how these techniques, and some brand new ones not possible ie process. This would look more natural, and require the gunner to "lead" the target, quite a challenge. You can also change the scoring rules to your liking, and of course, completely redefine the barriers and bug shapes. Have fun! Next month we'll adwn through the barrier and attack the gunner when their bodies have been shot away. You might also try to speed up the scrolling by just printing one third of the gun blast at a time, with scrolling in between, and then figure the hit out at the end of th that you can trade off memory space for tables, etc. for additional speed, then you can create some interesting things. There is certainly a lot you can do to make this month's game more interesting too. Try to figure out how to have the "heads" dive do prove something else as well. You don't need assembly language to get reasonable performance out of the Apple ///, even in the realm of programming generally thought to absolutely require it, games. If you're careful, use clever techniques, and remembergram, and won't be elaborated on. A Game a Day keeps Pac-man Away Sure, this game won't save you many quarters if you're an Arcade freak, and it's not exactly going to drive Bill Budge out of business, but hopefully the techniques will prove useful, and(22);CHR$(14); 510 TEXT:HOME 515 nam$=q$+"/BASIC/standard"+q$ 520 PERFORM getfont(@nam$,@array$):PERFORM loadfont(@array$) 525 PRINT CHR$(15); 530 CLOSE:INVOKE 540 END This is essentially identical to the routine used in the previous proxyERROR ?BUFPNT NT DEVINFO DEVINFO MOVESTR FILREAD FILREAD BUF :4 GETRFNM BUFPNT OJNT ERROR ROR DOARRAY e=TPARMSERROR uROR BUFPNT BMOVESTR REQNUM UUM BLDSTRN DSTRN BUF pia RETURN RETADR  GETPARMSFREQNUM BUF "CONTROL CONTROL RETURN RETADR GETPARMS TPARMSERROR ROR STATUS STATUS BLDSTRN ,BUF |F GETPARMSca` hhh5h66HH :5HHH) @  hhh g5ȱg6ȱg@ ɀL g eegghI8e556l6m `  hUhVh8 ㅊ eh֭VHUHk`HFB>;:9853/&" NL64Ch5h6h3lh4m 0/L6H5H`g8640'%76,V^dKA;6hWhXhhhQlhRm e Nb YMH YhLSꈭTXHWH`gca` hhh5h66HH :5HHH) @  hhh g5ȱg6ȱg@ ɀL g eegghI8e556l6m `  hUhVh8 ㅊ eh֭VHUHk`HFBhhHHHH l5m6m6  ЙW5X6X6 ` 5`MD32KA;6hWhXhhhQlhRm e Nb YMH YhLSꈭTXHWH`g##6 >?Bi{Ci|) |=! "LL{@?>8(O\ F9 >{i 5|i6) 6|8 L5{ hhhh0 hWhXXL `L5iklmnoGA3/1.01:7SY CONTROL FILWRITE FILWRITEGETRFNM RTRFNM ERROR ^ROR DOARRAY OARRAY   GETFONT "*:<"">""""""""""""">>><2"<""">""" ""  ">"6**"""""&*2""""""""""""*,"" "" ">""""""""""""""**6"""""""> >>> >00000>"uw>>< (&20 *, **>> "2*&" " >>  ">> "8""> """"""< >> " )((8*,;((*,((+)((9/(p((>3  =9 :9 .(+( 8#8# %3(8 ((,+)(%.4$)?((,(103  7  3  5  GETFONT GETFONT DOARRAY2QLOADFONT LOADFONTDOARRAY2ARRAY2 Y5ȱg6ȱg@ ɀLDg eegghI8e556l6m`  lmL}\ZYc&h:h; (+65;H:H`,.CONSOLEg<:/.-+*(% CX`hhh5h66HH :~5~HHH|})   |}) @  hhh ghzh{ Qghhh5h66 HHH566 qyhhhpx{HzH`~prstGA3/1.01:7SY <"<"""<< <"""<"><$""< """"  "" 6***""""""""""<""< :< $"""2,"""""**6"""""< >>8  80,>!30C$="N"C$="n"1160;:=23:=0::"79C";"PRESS ANY KEY TO HALT LISTING": $1020.202 8::Z=1B::=23:=0::"79C";"WOULD YOU LIKE A PRINTED COPY?":1C$:C$<>"Y"C$<>"y"C$<>"N"C$<>"n"1170*C$="N"C$="n";d$(y);vpencolor(%vector(pen)){moverel(%-140,%3)(p$=19)+" "+24)+" "+0)+" "+0)2draw$=p$+p$+p$+p$+p$+p$+p$+p$+p$+p$+p$:f$=f)) 20,31,35,41,48,66,75,96,115,126,140# -1,3,-1,6,-1,9,-1,12,-1,15,-1% 6,13,20,27,34,41,48,55,n(%2):#1;"=";:moverel(%-7,%-3):xfroption(%0):2pen=(pen<>4)*(pen)+1:pencolor(%vector(pen)):<pen=(pen<>1)*(pen-1)+4*(pen=1):pencolor(%vector(pen)):@moverel(%7,%-3):linerel(%133,%0):moverel(%-133,%0):620: ly=ylocq#1%0,%i):#1;d$(i);:viewport(%0,%139,%0,%192)0pen=1:moveto(%0,%7):pencolor(%vector(pen))#1;"=";:moverel(%-7,%0)a$:a=a$)!j(a)430,440,450,460,470,480410=xfroption(%2):#1;"=";:moverel(%-7,%3):xfroption(%0):>xfroptio|~tor(4)=yellow% 1160: set color prioritiesf=0: set fillcolor 3:=12:=20:"Setting up the game, please wait" 700: initialize screen map grafixonfillcolor(%f)2j(11)=1:j(10)=2:j(8)=3:j(21)=4:j(32)=5:j(13)=6),i=0191:moveto(d#1,".grafix"!id$(191),c%(10),l%(10),j(255)n".D1/bgraf.inv"Zxpurple%=3:blue%=6:orange%=9:green%=12:white%=15:dgreen%=4:brown%=8:grey%=10:yellow%=13grafixmode(%3,%1)initgrafixHvector(1)=dgreen%:vector(2)=brown%:vector(3)=grey%:vecgrafixmode(%3,%1)!(fillcolor(%5):pencolor(%13)7grafixon:fillport <y=110 Ai=023Fmoveto(%0,%191)K#1;scr$(i);LiMy Za$:Za$: scr$(23) ".D1/bgraf.inv" lf$=13)+10)#1,".grafix"s$="*"+lf$b$=" "+lf$Nm$=b$+s$+s$+b$+b$+b$+s$+s$+s$+b$+s$+s$+s$+s$+b$+b$+s$+s$+b$+s$+s$+s$+b$+s$x1=023:x=x1*3&scr$(x1)=m$,73-x,x)+m$,1,72-x)x1initgrafixCESS3.INV"'<:=30::"WELCOME TO ACCESS ///":4F=3:=22:"WHICH SY"Returning you now to the Menu.Maker program."d".D1/MENU.MAKER"******** : œ15:""DATE IS: ";:"TIME IS ";L"PRESS IF OKAY, N)o TO CHANGE:";:OK$:"NO",OK$)"TIMESET"(#1,".RS232"%2A$=:="":"/APPLCOM/ACEAD PASCAL TEXT FILES."04=10:"78C";"ANY KEY RETURNS TO THE MENU."!>G$:::".D1/MENU.MAKER",320R",220(204::"79A";""; 2D=1:F=1 <#4;a$ FD=D+1 P#5;a$ZD=60#5;12)dD=60D=1nF=F+1::d$;::Y=1100:Y x13402  CATCH PASCAL TEXT FILES 202 :F*=08:"78C";"SORRY BUT MENU.MAKER CAN'T R".D1/MENU.MAKER",220 d$="" A$="PRINTING "+B$(I),16,B)=01:=0::"80C";A$;:#3,B$(I),16,B)Z=1#3;b$:"78A";b$Z=Z+1:Z=18:1290 1260 #4,B$(I),16,B)#5,".PRINTER"+ž#4#5;12):::".D1/MENU.MAKE62,69,76k=010:l%(k):+k=010:c:c<0c%(k)=f:::c%(k)=c:@k=010:draw$,7*k+2,1)=c%(k)):draw$,7*k+4,1)=l%(k)):k=010:lk(k):Ak=0191:y$=k):j=010:draw$,lk(j),1)=y$::d$(k)=draw$:( 39,141,29,161,49,181,19,191,14,171k=04:bot(k),top(k):k=04:in=14*k+9"j=0bot(k):d$(j),in,1)=f$:$j=top(k)191:d$(j),in,1)=f$:k $setctab(%dgreen%,%blue%,%blue%)(setctab(%dgreen%,%orange%,%orange%)&setctab(%dgreen%,%green%,%green%)&s& Shape, Character and Font EditorH char%(127,15),shape%(7,15),name$(10),ary$(10),size%(10),bits%(15,3)Gwork%(7,15),shex%(15,3),cset%(511),lookup(15),flip(255),block$(15)*"Initializing variables, please wait" 40009".D1/bgraf.inv","..&"&""` ,2"2l"><$,22, &""w  0 "2 # ***+&""#"""&&l22, `&< $g""2lg""c***6ccg""< >$>88  !-3>">""w"""""""""""?"  "??""r""w"">""w>**>8c  g"?c6**""w#&*2""w"""""""!!!)."""w1 #Iw"""""w""""c""**6"c""cw"">""> "$$$>>< (#21*,*>*>> "2*&" >" ">"  "?8>" """">"""""""< "00>> " =w2x?UpU%CAH0>cGM&>ww8DB"?37=]>U6U6>0|~?r|8?x`0|p0?0?0~~@ @@p 0|~vr|8tyr492<0O'N&$D @Pb#BB$8~k""f/!F<Dh8~W"/{C?@@  >6>6 P"YEEY" a%(511)array$="a%"".D1/download.inv"a$="standard":8001 name$=34)+a$+34):getfont(@name$,@array$)*loadfont(@array$)release:release:releasei:nss ".D1/bgraf.inv"#1,".grafix"1m$=" ** **** ** **** *** * **** ** ***"initgrafixgrafixmode(%3,%1)!#fillcolor(%4):pencolor(%13) (fillport -grafixon 2i=01397moveto(%i,%180):#1;m$<iAa$:a$)<>2750d%)etctab(%dgreen%,%white%,%white%)'setctab(%brown%,%orange%,%orange%)%setctab(%brown%,%green%,%green%)%setctab(%brown%,%white%,%white%)$setctab(%grey%,%green%,%green%)$setctab(%grey%,%white%,%white%)&setctab(%yellow%,%white%,%white%)D1/request.inv",".D1/download.inv"##1,".grafix"(initgrafix-grafixmode(%2,%1)!2fillcolor(%15):pencolor(%0)97::"Initializing the graphics screen, please wait."(<viewport(%0,%559,%0,%191):fillportAmoveto(%0,%184)[F#1;"=========ile$=line$Fy3)=8message$="INVALID, "+line$+" is a TEXT file.":3100:1125~3)=01170>prompt$="Ok to destroy old data in file "+file$+"? ":3000fin1125!"Yy",line$,1,1))11253filtyp<>3#3,0;filtyp,ch,cw,sl:#3,1;0:#3,prompt$="Save as a "+name$(1)+", "+name$(2)+" or "+name$(3)+"? "V3000:fin2[a$=line$,1,1):filtyp=" Ss Cc Ff",a$)/3)`filtyp=01105+eprompt$="Pathname of Save file: ":3000"jfinchoice=1::fin1105 oœ1190 t#3,line$vf5,%540,%71,%88):fillportlviewport(%0,%559,%0,%191)q clean up and go home5prompt$="Quit the Shape Editor? (Y to confirm): " 3000"Yy",line$):release:release:release Lchoice=1filtyp=1:1125DQnval=-cnval.cval$,nibpos+1,1)=nib$)+cnval),4,1) work%(col,15-cvert)=cval$)cstate=cstate*Xviewport(%5,%556,%131,%166):fillport*]viewport(%5,%135,%101,%118):fillport,bviewport(%155,%420,%101,%118):fillport(gviewport(%2):drawimage(@shex%(0,0),%32,%24+cstate*4,%0,%4,%1)'col=chorz/16):bitnum=chorz-col*16Lcval$=work%(col,15-cvert)):nibpos=bitnum/4):nib$=cval$,nibpos+1,1)1bit=bitnum-nibpos*4:cstate=bits%(nib$),bit))cnval=2^(3-bit):cstatecert*2+134):drawimage(@shex%(0,0),%32,%24+cstate*4,%0,%4,%2)Omoveto(%chorz+7,%cvert+102):drawimage(@shex%(0,0),%32,%6+cstate,%3,%1,%1)Vmoveto(%chorz*2+157,%cvert+102):drawimage(@shex%(0,0),%32,%12+cstate*2,%2,%2,%1)Smoveto(%chorz*4+7,%cvert+7rz=chorz+skp:450:340::3405Etop>=cvert+skpcvert=cvert+skp:450:340::3405Jbot<=cvert-skpcvert=cvert-skp:450:340::340,O450:470:400:ch<15-cvertch=15-cvert$Tmoveto(%chorz*4+7,%cvert*2+134) Y280^Vmoveto(%chorz*4+7,%cv,%24+cstate*4,%0,%4,%2)key=:key=27kvl=0::210("key>127skp=cw:key=key-128::skp=1'kvl=ctrl$,key)),,kvlkvl315,320,325,330,335,1500,1700 128066;left<=chorz-skpchorz=chorz-skp:450:340::3407@right>=chorz+skpcho300,250,1500,1700,2500,1900:2103070:210450cflash=cstate 280$ moveto(%chorz*4+7,%cvert*2+134)5drawimage(@shex%(0,0),%32,%24+cflash*4,%0,%4,%2)1cflash=cflash:z=15+200*(cstate)::270::drawimage(@shex%(0,0),%v32%#1;" 1 : Save 4 : Edit 7 : Define"Imoveto(%69,%27):#1;" 2 : Load 5 : Invert 8 : View" grafixon prompt$="Select a Command: " 3000fin=21000a=line$,1,1))Ga>47a<57a-471200,1100,1400,11;" 140 X 192 ";*moveto(%233,%67):#1;" Command Keys "fmoveto(%7,%57):#1;" Arrow keys move cursor ESCAPE quits current mode SPACE toggles bits";Jmoveto(%69,%45):#1;" 0 : Catalog 3 : Delete 6 : Clear"Kmoveto(%69,%36):oveto(%261,%176):#1;" Work Area "d600(}viewport(%5,%556,%13,%58):fillport'viewport(%5,%556,%1,%10):fillportviewport(%0,%559,%0,%191)(moveto(%28,%128):#1;" 560 X 192 ";)moveto(%253,%128):#1;" 280 X 192 ";(moveto(%233,%98):#=======================================================================";Kmoveto(%0,%191)!P#1"79c";"DrawImage Editor"[U#1;"================================================================================";!Zfillcolor(%0):pencolor(%15)(_m1choice3750,3850,3860choice<>filtyp2000filtyp=33950<array$=ary$(filtyp):filwrite(%3,@array$,%size%(filtyp))choice=33950#filtyp=3cftype(@file$,@v7%)3#3::message$=name$(filtyp)+" saved.":3100::message$="Error in opening or writing to file. ":3100 :1125#prompt$="Pathname to Catalog: " 3000findelay=1: oldpre$= œ1270 =line$ #8, ž#81285 delay=0#8;message$(message$,1,10)=" "1250 31rring Character set format to Font format":3100k=063:j=8*k-18i=072:j=j+1:a$=char%(k,i)):b$=char%(k,i+1))#cset%(j)=a$,1,2)+b$,1,2))%cset%(j+4)=a$,3,2)+b$,3,2)):> prompt$="Character height is now "+ch+1)+"k=063:j=8*k-14>i=072:j=j+1:a$=cset%(j)):b$=cset%(j+4))%Cchar%(k,i)=a$,1,2)+b$,1,2))'Hchar%(k,i+1)=a$,3,2)+b$,3,2))M:'Rk=64127:i=07:char%(k,i)=0::'Wk=0127:i=815:char%(k,i)=0::\Emessage$="Transfe:+600:1700?:prompt$="Character height is now "+ch+1)+". New value: ";lchoice=13605:qchoice=23850::3860 v3800 {3605filtyp3750,2100,2200E4message$="Transferring Font format to Character set format":31009450:cstate470:400 17009cloc=chorz/16):chalf=(chorz-16*cloc>7):st=chalf*2+1 i=0ch:b$=work%(cloc,i))(b$,st,2)="00":work%(cloc,i)=b$):bw=cloc:ew=cloc:rs=0:re=ch3610:1700,&crow=0ch:i=0sl:work%(i,crow)=0:3500:450:340 fina$=line$,1,1) a=" Rr Cc Bb Ww",a$)/3)a3060:1700a1740,1760,1800,1830crow=15-cverti=0sl:work%(i,crow)=0:rs=crow:re=crow:bw=0:ew=sl3610:1700cur.vert=cvertcvert=15-ch15:ew=cloc:rs=0:re=ch^3610:1500,hcrow=0ch:i=0sl:b$=work%(i,crow))Jmwork%(i,crow)=255-b$,1,2))),3,2)+255-b$,3,2))),3,2))r:w3607:15006prompt$="Clear Row, Column, Block or Work space? " fst=0$3000:finkvl"cur.vert=cvert'cvert=15-ch15,450:470:40016cvert=cur.vert ;15009@cloc=chorz/16):chalf=(chorz-16*cloc>7):st=chalf*2+1 Ei=0ch:b$=work%(cloc,i)))Jb$,st,2)=255-b$,st,2))),3,2)Owork%(cloc,i)=b$)TiYbw=cloc1) a=" Rr Cc Bb Ww",a$)/3)a3060:1500a1540,1570,1600,1640crow=15-cvert i=0sl:b$=work%(i,crow))Jwork%(i,crow)=255-b$,1,2))),3,2)+255-b$,3,2))),3,2))rs=crow:re=crow:bw=0:ew=sl3610:1500 œ1455 #3,line$-filread(%3,@array$,%size%(choice),@ret%) :#3,ret%<>size%(choice)1480::3950:14857prompt$="Invert Row, Column, Block or Work space? " fst=0$3000:finkvl3500:450:340 fina$=line$,1,:choice=31420%#3:3)=0line$:1420::14203#3,1:filread(%3,@array$,%size%(filtyp),@ret%)!#3:ret%=size%(filtyp)1485Bmessage$=name$(choice)+" in "+line$+" is invalid.":3100:14201message$=name$(choice)+" loaded.":3100:3600400 œ14553array$=ary$(choice):choice<>3#3,line$:1450 œ14929ch=7:font$=34)+line$+34):getfont(@font$,@array$):3950:148553)=1#3;filtyp,ch,cw,sl:filtyp=choice14702message$="Not a "+name$(choice)+" file.":3100ocked)"n3100:1300Exprompt$="Load a "+name$(1)+", a "+name$(2)+" or a "+name$(3)+"? "}3000:fin2a$=line$,1,1):choice=" Ss Cc Ff",a$)/3)$choice<1choice>33070:1400-prompt$="Pathname of "+name$(choice)+": "3000:fin1le":3100:#8:1300 2œ13807#8:line$<Amessage$=line$+" deleted."F3100:1300PJUmessage$="Cannot delete "+line$+". (doesn't exist or can't be opened)"Z3100:1300dCimessage$="Cannot delete "+line$+". (write-protected or l00a$:a$)=271285:ۺ1250+message$=line$+" is not a valid Prefix"delay=1:3100 =oldpre$ 1200*prompt$="Pathname of file to Delete: " 3000 fin #œ1360(#8,line$B-8)<>1message$=line$+" is not a Save fi. New value: " 3000:fin2550 a=line$)P a<1a>16message$="Character height must be between 1 and 16":3100:2500@ ch=a-1:message$="Character height is now "+ch+1)+".":3100; prompt$="Character width is now "+cw)+". New value: " 3000:fin2600 a=line$)Q a<1a>255message$="Character width must be between 1 and 255":3100:2550; cw=a:message$="Character width is now "+cw)+".":3100M( prompt$="Work area width in dots (must be 16,32,48,64,80,96,112 or 128: "- 3000:"4ary$(1)="shape%":ary$(2)="char%":ary$(3)="cset%",size%(1)=256:size%(2)=2048:size%(3)=1024.ctrl$=8)+21)+11)+10)+32)+"5"+"6":left=0:right=127:top=15:bot=0:cvert=15:chorz=0:delay=1delay=1p=15:bot=0:cvert=15:chorz=0:dei=015:j=03:bits%(i,j)::v256=256:v16=16:v7%=7Mi=0255:a$=i):flip(i)=v16*lookup(a$,4,1)))+lookup(a$,3,1))):2sh=7:sl=7:ch=7:cw=8:choice=2:wd=0:skip=0:fst=1Hname$(1)="Shape definition":name$(2)="Character set":name$(3)="Font,0,1,1,1E 1,0,0,0,1,0,0,1,1,0,1,0,1,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,1,1,1,1i=015:block$(i)::i=015:h%=block$(i)):shex%(i,0)=h%:shex%(i,1)=h%:"i=07:a$:shex%(i,2)=a$):"i=03:a$:shex%(i,3)=a$):i=015:lookup(i):$0,000F,00F0,00FF,0F00,0F0F,0FF0,0FFF- F000,F00F,F0F0,F0FF,FF00,FF0F,FFF0,FFFF- 0003,0C0F,3033,3C3F,C0C3,CCCF,F0F3,FCFF 0123,4567,89AB,CDEF, 0,8,4,12,2,10,6,14,1,9,5,13,3,11,7,15 E 0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,1,0,0,0,1,0,1,0,1,1,0b$=cset%(j+4))%Uwork%(k,i)=a$,1,2)+b$,1,2))'Zwork%(k,i+1)=a$,3,2)+b$,3,2))_:d2nmessage$="Preparing the character font.":3100Xsk=0511:b$=cset%(k)):cset%(k)=v256*flip(b$,1,2)))+flip(b$,3,2))))):x- 000#cset%(j)=a$,1,2)+b$,1,2))%#cset%(j+4)=a$,3,2)+b$,3,2))(:-A<cr>127message$="Character range must be 0-127":3100:3800.Fskip=4*cr:sl=7:cr+2*sl>126sl=(126-cr)/2Kk=0sl:j=skip+8*k-14Pi=072:j=j+1:a$=cset%(j)):n (0,2,4,etc.)":3100:3800&wd=cr/2:sl=7:wd+sl>127sl=127-wd2i=0ch:j=0sl:work%(j,i)=char%(wd+j,i)::2 i=0ch:j=0sl:char%(wd+j,i)=work%(j,i)::k=0sl:j=skip+8*k-18i=072:j=j+1:a$=work%(k,i)):b$=work%(k,i+1))j)=work%(i,j)::4prompt$="Starting Character number to display: " 3000fincr=0:3822cr=line$)=cr<0cr>254message$="Number out of range":3100:3800choice=33900Ucr/2<>cr/2)message$="Character number must be evemoverel(%width*4,%0):36955`a$=work%(i,k)):j=14:dhex%=a$,j,1))*width9edrawimage(@shex%(0,0),%32,%dhex%,%srow,%width,%rows)jmoverel(%width,%0):o:r/ti=07:j=0ch:work%(i,j)=shape%(i,j)::y/i=07:j=015:shape%(i,(@work%(0,0),%16,%0,%0,%128,%ch+1)+.xdot=157:ydot=117:rows=1:width=8:srow=2 33670)8xdot=7:ydot=87:rows=1:width=16:srow=0 =3670 Bfst=1GVxhorz=xdot+16*bw*(width/4)4[k=rsre:moveto(%xhorz,%ydot-rows*k):i=bwew3]fstwork%(i,k)=0#1;message$;0 i=1750*delay:: ' viewport(%5,%556,%1,%10):fillport viewport(%0,%559,%0,%191) choice3700,3800,3800600rs=0:re=ch:bw=0:ew=sl*xdot=7:ydot=164:rows=2:width=16:srow=0 3670$moveto(%7,%117)0)drawimage line$)=03015. moverel(%-7,%0):#1;" ";:moverel(%-7,%0) line$=line$,1,line$)-1) 3015 print an error message moveto(%450,%9) #1;"INVALID";:i=1500: moveto(%450,%9) #1;" ";  3500 & moveto(%7,%9):*K message$="Definitions complete.":3100P & Accept a message from the window% 3500:moveto(%7,%9):#1;prompt$; line$="":fin=0 a$:a=a$)' a>31#1;a$;:line$=line$+a$:3015 a=13fin=(line$)=0): a=27fin=2: a<>83015fin26402 a=line$)/16-1C7 a)<>amessage$="Width must be a multiple of 16":3100:2600F< a<0a>7message$="Width must be between 16 and 128":3100:2600EA sl=a:message$="Work area width is now "+(a+1)*16)+".:gosub 3100F right=(a+1)*16-1lay=1p 32.:gosub 3100%.:gosub 3100 Work area width is now 3232Work area width is now  32233Work area width in dots (must be 16,32,48,64,80,96,112 or 128: ?Character width is now 16..Character wi Atest.shapeA%Pathname of Save file: A.8A0AA0ADefinitions complete.A  56Acset%char%shape%FontCharacter setShape definitionFFFFFFF0FF0FFF00F0FFF0F0F00FF0000FFF0FF00F0F0F0000FF00F0000F0000p@ 32.:gosub 3100%.:gosub 3100 Work area width is now 3232Work area width is now  32233Work area width in dots (must be 16,32,48,64,80,96,112 or 128: ?Character width is now 16..Character wi Atest.sh191):fillport*<viewport(%133,%139,%0,%191):fillportAfillcolor(%4)Fviewport(%0,%139,%0,%191) KgrafixonPj=7-77-1Umoveto(%j,%180):#1;m$Zj_a$:a$)<>2780drelease:release:releasei:nss ".D1/bgraf.inv"#1,".grafix"3m$=" ** **** ** **** *** * **** ** *****"initgrafixgrafixmode(%3,%1)#pencolor(%13)(fillcolor(%4):fillport*-setctab(%4,%9,%9):setctab(%13,%9,%9)2fillcolor(%9)&7viewport(%0,%6,%0,%Berror=0:: Shape loaded œ1030array$="shape%":#3,file$03)=1#3;filtyp,ch,cw,sl:filtyp=11070 :#33)=0file$error=1: Not a shape file$0.#3,1:filread(%3,@array$,%256,@ret%)::#378ret%<>256error=2:: Shape definition is invalid @ @ (' `@ @5X*EDJ @apeA%Pathname of Save file: A.8A0AA0ADefinitions complete.A  56Acset%char%shape%FontCharacter setShape definitionFFFFFFF0FF0FFF00F0FFF0F0F00FF0000FFF0FF00F0F0F0000FF00F0000F0000p 32.:gosub 3100%.:gosub 3100 Work area width is now 3232Work area width is now  32233Work area width in dots (must be 16,32,48,64,80,96,112 or 128: ?Character width is now 16..Character wi Atest.shapeA%Pathname of Save file: A.8A0AA0ADefinitions complete.A  56Acset%char%shape%FontCharacter setShape definitionFFFFFFF0FF0FFF00F0FFF0F0F00FF0000FFF0FF00F0F0F0000FF00F0000F0000p 32.:gosub 3100%.:gosub 3100 Work area width is now 3232Work area width is now  32233Work area width in dots (must be 16,32,48,64,80,96,112 or 128: ?Character width is now 16..Character wi Atest.shto(%k+14,%l)0drawimage(@shape%(0,0),%s%,%r%,%z%,%s%,%s%)moveto(%k,%m)1drawimage(@tshape%(0,0),%s%,%r%,%z%,%s%,%t%)ka$:a$)<>27105,release:release:release6:@J œ1030array$="shape%":#3,file$03)=1wport(%40,%100,%15,%130)<fillcolor(%13):fillport Agrafixonds%=16:t%=32:z%=0 ik=0100nj=k/5+2)*53+88sl=k/10)*30+58xm=k/10)*70+85}r%=t%+s%*(r%=t%)moveto(%k+28,%j)1drawimage(@tshape%(0,0),%s%,%r%,%z%,%s%,%t%)move shape%(7,15),tshape%(7,31)&".D1/bgraf.inv",".D1/request.inv"#1,".grafix"file$="next.shape":10003j=015:i=07:tshape%(i,j+8)=shape%(i,j)::#initgrafix(grafixmode(%3,%1)-pencolor(%4)2fillcolor(%7):fillport 7vie 1984,2080 2080,4752 4752,4112 4112,5008 5008,2080 2080,1984 1984,2336 2976,2720  1344,4752  0,0  0,0  0,0 0,0rawimage(@zshape%(0,0),%f%,%r%,%z%,%s%,%t%)ka$:a$)<>27105,release:release:release6:@J&j=015:i=01:mshape%(i,j)::4j=015:i=01:zshape%(i,j+8)=mshape%(i,j)::  0,0  0,0  0,0  0,1984f%=4 ik=0100nj=k/5+2)*53+88sl=k/10)*30+58xm=k/10)*70+85}r%=s%*(r%=z%)moveto(%k+28,%j)1drawimage(@zshape%(0,0),%f%,%r%,%z%,%s%,%t%)moveto(%k+14,%l)1drawimage(@mshape%(0,0),%f%,%r%,%z%,%s%,%s%)moveto(%k,%m)1d mshape%(1,15),zshape%(1,31)".D1/bgraf.inv"#1,".grafix" 1000#initgrafix(grafixmode(%3,%1)-pencolor(%4)2fillcolor(%7):fillport 7viewport(%40,%100,%15,%130)<fillcolor(%13):fillport Agrafixonds%=16:t%=32:z%=0:@@@@  ( ' ' @@  @@ ** @@@% apeA%Pathname of Save file: A.8A0AA0ADefinitions complete.A  56Acset%char%shape%FontCharacter setShape definitionFFFFFFF0FF0FFF00F0FFF0F0F00FF0000FFF0FF00F0F0F0000FF00F0000F0000#3;filtyp,ch,cw,sl:filtyp=11070 :#33)=0file$ error=1: Not a shape file $0.#3,1:filread(%3,@array$,%256,@ret%)::#388ret%<>256error=2:: Shape definition is invalid Berror=0:: Shape loaded : Shape loaded The Third Basic by Taylor Pohlman >47<58pause=-48 20021);"="22);14);:nam$=q$+".D1/standard"+q$.getfont(@nam$,@array$):loadfont(@array$) &15);0Xtext40$;bw$;:bloadfont(@array$) li=111vm$i""Name of font nname$=".console",xctrlist1$=2)+23)+head1$+21)+tail1$,ctrlist2$=2)+23)+head2$+21)+tail2$ 2002control(%17,@ctrlist1$)name$:i=110*pause:2control(%17,@ctrlist2$)name$:i=110*pause:150=27500 a%(511))".D1/download.inv",".D1/request.inv"q$=34):array$="a%"(fg$=19):bg$=20)2mblue$=6):white$=15)<bw$=fg$+mblue$+bg$+white$Ftext40$=16)+1)P700: get font Z800: load up the bugs d600: set up screen ,0  0,0  0,0  0,1984  1984,2080  2080,4752  4752,4112  4112,5008  5008,2080  2080,1984  1984,2336  2976,2720   1344,4752  0,0  0,0  0,0 0,0 y%(10)=-3 Ai=70:j=90Fmoveto(%i,%j)Kr%=0r%=16:r%=00Pdrawimage(@shape%(0,0),%f%,%r%,%z%,%s%,%s%)Ua$:a=a$)#Za<>27i=i+x%(a):j=j+y%(a):70drelease:release:releasei:ns%j=015:i=01:shape%(i,j)::  0!shape%(1,15),x%(127),y%(127) ".D1/bgraf.inv"#1,".grafix" 1000initgrafixgrafixmode(%3,%1)!#fillcolor(%4):pencolor(%13) (fillport-viewport(%0,%139,%0,%191) 2grafixon7f%=4:s%=16:z%=0(<x%(8)=-3:x%(21)=3:y%(11)=3:r37SMOOTH.SCROLL 2&SWITCH 3 *TEST.SHAPE 2M QUICK.FONT.DUMP 4,READ.BUBBLES 2(READ.WAG )47SCROLL.HIRES .1-SCRUB.BUBBLES 3SHAPE.LOAD.SUB  2M()SHORT.WAG file: ";flname$name$=q$+flname$+q$getfont(@name$,@array$)+head1$="":head2$="":tail1$="":tail2$="" i=9295hd$=a%(i))3head1$=head1$+hd$,1,2)))+hd$,3,2)))ii=104107hd$=a%(i))3head2$=head2$+hd$,1,2)))+hd$,3,2)))i i=8487tl$=a%(i))3tail1$=tail1$+tl$,1,2)))+tl$,3,2)))i i=9699tl$=a%(i))3tail2$=tail2$+tl$,1,2)))+tl$,3,2)))i@ char$(0)=" ":char$(1)=149):char$(2)=150):cha2)))3body1$=body1$+b1$,1,2)))+b1$,3,2)))3body2$=body2$+b2$,1,2)))+b2$,3,2)))3tail1$=tail1$+t1$,1,2)))+t1$,3,2)))3tail2$=tail2$+t2$,1,2)))+t2$,3,2)))i!  7215,7215,14462,14462,0,0 )head1$="":head2$="":body1$="":body2$="":tail1$="":tail2$="" i=14a%,b%,c%,d%,e%,f%+h1$=a%):h2$=b%):b1$=c%):b2$=d%)t1$=e%):t2$=f%)3head1$=head1$+h1$,1,2)))+h1$,3,2)))3head2$=head2$+h2$,1,2)))+h2$,3,=27500>47<58pause=-48 20021);"="22);14);:nam$=q$+".D1/standard"+q$.getfont(@nam$,@array$):loadfont(@array$) &15);0Xtext40$;bw$ b:: li=111vm$i?nname$=".console"9xctrlist1$=3)+23)+head1$+22)+body1$+21)+tail1$9ctrlist2$=3)+23)+head2$+22)+body2$+21)+tail2$ 2002control(%17,@ctrlist1$)name$:i=110*pause:2control(%17,@ctrlist2$)name$:i=110*pause:150 a%(511))".D1/download.inv",".D1/request.inv"q$=34):array$="a%"(fg$=19):bg$=20)2mblue$=6):white$=15)<bw$=fg$+mblue$+bg$+white$Ftext40$=16)+1)P700: get font Z800: load up the bugs d600: set up screen &15);0);0$) &15);0ctrlist2$=1)+65)+ltr.a$!control(%17,@ctrlist1$)name$a$:a$)=27500!control(%17,@ctrlist2$)name$a$:a$)<>2715021);"="22);14);:nam$=q$+".D1/standard"+q$.getfont(@nam$,@array$):loadfont(@array$)+lt$,1,2)))+lt$,3,2)))AiFi=264267Klt$=a%(i))3Pltr.b$=ltr.b$+lt$,1,2)))+lt$,3,2)))UiZloadfont(@array$)_text40$:)di=110:"ABABABABABABABABABABAB":inname$=".console"xctrlist1$=1)+65)+ltr.b$ a%(511))".D1/download.inv",".D1/request.inv"q$=34):array$="a%"text40$=16)+1)""Name of font file: ";flname$#name$=q$+flname$+q$(getfont(@name$,@array$)-ltr.a$="":ltr.b$=""2i=2602637lt$=a%(i))3<ltr.a$=ltr.a$r$(3)=151)1*m$=".23...123.1223..13.123.3.23...123.1223..",4i=140:m$,i,1)=char$(m$,i,1))):i>i>m$,i,1))):i> 32545,31555,27519,22399,1090,580 ( 838,16156,32546,32546,16932,26640  15360,0,8806,4369,6144,0 @ char$(0)=" ":char$(1)=149):char$(2)=150):char$(3)=151)1*m$=".23...123.1223..13.123.3.23...123.1223..",4i=140:m$,i,1)=char$(m$,i,1))):i>",32546,16932,266402,26640,32546,16932,26640ntrol(%17,@ctrlist$(7))name$7first$;:i=814:control(%17,@ctrlist$(i))name$:x=03825n$(x);:i=07:control(%17,@ctrlist$(i))name$:8n$(x+1);:i=814:control(%17,@ctrlist$(i))name$:xerasend$;:=+1155 Process khead definitionsZ800: load the print lined600: set up screen ni=062xctrlist$(i)=2)+0)+head1$(i)+1)+head2$(i)}i i=7136ctrlist$(i)=2)+0)+head2$(i-7)+1)+head1$(i-7)ictrlist$(14)=ctrlist$(0) 200#co4 a%(511),ctrlist$(14),head1$(6),head2$(6),n$(39))".D1/download.inv",".D1/request.inv")q$=34):array$="a%":name$=".console"(fg$=19):bg$=20)2mblue$=6):white$=15)<bw$=fg$+mblue$+bg$+white$Ftext40$=16)+1)#P700: get the .&"&""` ,2"2l"><$,22, &""w  0 "2 # ***+&""#"""&&l22, `&< $g""2lg""c***6ccg""< >$>88  !-3>">""w"""""""""""?"  "??""r""w"">""w>**>8c  g"?c6**""w#&*2""w"""""""!!!)."""w1 #Iw"""""w""""c""**6"c""cw"">""> "`` `@ @@@@?##21*,*>*>> "2*&" >" ">"  "?8>" """">"""""""< "00>> " =w2x?UpU%CAH0>cGM&>ww8DB"?37=]>U6U6>0|~?r|8?x`0|p0?0?0~~@ @@p 0|~vr|8tyr492<0O'N&$D @Pb#BB$8~k""f/!F<8^~B xp<| p`xx0`@pp0`@ a%(511)".D1/download.inv"nam$=q$+"move.bug.2"+q$(getfont(@nam$,@array$)J2i=0122:a1=(i+23)*4:a2=(i+24)*4:j=03:a%(a1+j),a%(a2+j):j::i<i<eystrokes =27500 20021);"="22);14);:nam$=q$+".D1/standard"+q$.getfont(@nam$,@array$):loadfont(@array$) &15);0Xtext40$;bw$]21);"9"; b::l i=06head1$(i)="":head2$(i)="" j=03a%:h$=a%)7head1$(i)=head1$(i)+h$,1,2)))+h$,3,2)))j j=03a%:h$=a%)7head2$(i)=head2$(i)+h$,1,2)))+h$,3,2)))ji" 7215,32545,838,15360,0,0,0,0& 14430,32322,1548,307use of "3-byte", 24 bit pointers. 3-byte pointers take up more space, however, and therefore are only used when it makes sense. The designers of Business Basic built in several such limits to save space and improve performance. For example, you are only that limits like 64K keep coming up relates to the fact that a 16 bit pointer can store all the possible addresses in a 64K address space (2^15-1=65535). The Apple /// can address more than 64K because it uses "extended indirect addressing", which makes es someday will cover all the tricks you can do with the "CHAIN" statement to break your program up into logical segments. But, the question deserves an answer, and in doing so, we'll note some other limits of Business Basic as well. One of the reasonsSIC program statements cannot total more than 64K, excluding variable and array space, etc. This question rarely comes up, because 64K is enough space for over 3000 program lines, which is a very impractical size for a single program. One of these articlpplications on the Apple ///. But First, A Word from our Sponsors The mailbag this month brought a couple of items of general interest. First, the question came up as to why Business Basic does not allow programs larger than 64K bytes. That is, the BAemendously to the effectiveness and readablity of your screen displays. For proof of this statement, take a look at Apple's Mail List Manager program some time. Special character sets in that program make it one of the best appearing and easiest to use ainess Basic wasn't exactly designed for games (the name is one clue!), but with careful design, reasonably performing graphics is possible, and that has a lot of business applications. In fact, the concept of redefining characters to new shapes can add tr nce to see the March article in this series, 'cause there's going to be lots of information in this month's missive which will build on that exploration of character graphics and the associated game which was dubbed "Bug-Mania". As was said last time, Bus T H E T H I R D B A S I C by Taylor Pohlman Exploring Business Basic, Part 19 Here's hoping all of you got a cha*i=1372(4n$(i)=24)+i-1)+" "+129)+128)(>n$(i+1)=24)+i)+" "+128)+129)Hi!Rn$(39)=24)+38)+" "+129)\erasend$=24)+39)+" "ffirst$=24)+0)+128)p8)p)+0)+128)p20,0,256,1,0( 28732,31748,3096,28672,1,769,2,256+ 24696,30728,6192,24576,258,1794,4,768-  16496,28688,12384,16384,773,3844,8,1792(  96,24608,24640,0,1803,7944,17,3840* 64,16448,16384,0,3607,16144,291,7680" n$(0)=24)+0)+128)+129) allowed to have 64K of string variable space and 64K of simple numeric variable space. You are allowed as many numeric arrays as will fit, but each one must be no more than 64K. These may sound like limits, but remember, most personal computer Basics have an absolute limit of 64K of total space, program, data, the works. Ask your friends with an IBM PC what they get when they type FRE - right, about 61K no matter how much memory (above 128K) is actually installed! It would be remiss to not note anothermodule uses a string variable as the parameter list, it is necessary to convert the contents of the integer array a% into equivalent ASCII characters. This is done in lines 55-60 and 75-80 by first converting the integer into HEX format, and then treating lt$=HEX$(a%(i)) 80 ltr.b$=ltr.b$+CHR$(TEN(MID$(lt$,1,2)))+CHR$(TEN(MID$(lt$,3,2))) 85 NEXT i The routine above looks a little complicated, but it's really straight-forward. Since the SOS Control call mechanism in the "request.inv" invokable ns manually. The next section extracts two character definitions: 45 ltr.a$="":ltr.b$="" 50 FOR i=260 TO 263 55 lt$=HEX$(a%(i)) 60 ltr.a$=ltr.a$+CHR$(TEN(MID$(lt$,1,2)))+CHR$(TEN(MID$(lt$,3,2))) 65 NEXT i 70 FOR i=264 TO 267 75 ame$,@array$) The lines above set up the array which will hold an alternate character set, invoke the necessary modules, and load the font into the "a%" array. Although we don't need all these characters, it saves us the trouble of entering the definitio's try the following program: 10 DIM a%(511) 15 INVOKE"/basic/download.inv","/basic/request.inv" 20 q$=CHR$(34):array$="a%" 25 text40$=CHR$(16)+CHR$(1) 30 INPUT"Name of font file: ";flname$ 35 name$=q$+flname$+q$ 40 PERFORM getfont(@nbout how is works in in the Standard Device Drivers manual in the section on the Console driver. Basically, it allows you to change up to 8 character definitions "on the fly", and it does this very fast. To give you a feel for how this process works, lete advantage of a little-known capability of the .Console driver, the partial character download feature. This is a "control" call to the driver (remember our previous sessions about console capabilities?), specifically control call 17. More information aand other purposes. For example, suppose you wanted to change every occurance of one character shape on the screen to another shape. You could simply re-print the character, and rely on the fact that printing in text mode is pretty fast, or you could tak can be tough to tell whether the action is occurring in text mode or graphics, especially if you do a lot of work with the character definitions. There are, however, other ways to accomplish the rapid changing of characters on the screen for animation d by redefining certain characters, and then printing them rapidly to the screen, taking advantage of the fact that printing to the text screen goes very rapidly, compared to writing to the graphics screen. Since the Apple /// has a 16 color text mode, itirer and to the rest of you in a later column. Back to Work Last time, as you may remember, we used the fact that the Apple /// has a RAM-based, and therefore modifiable, character set to create some high speed animation effects. These were accomplisheess Graphics package supports the Qume, producing hi-res screen dumps and other graphic images, but those routines are written in Pascal. If anybody has developed Qume output routines, drop a note in care of Softalk and it will be passed along to the inquven if it could be written. So now you know. The other question is one for which this columnist has no ready answer, so your comments are solicited. It concerns supporting the Qume letter quality printer as a graphics output device. The Apple /// Busin, though more esoteric reason for the program size limit. Since Business Basic saves and loads programs with a single SOS call, and SOS has a 64K limit on the total number of bytes in a single read or write, it would be impossible to use such a program, e the result as a pair of two digit HEX numbers which are converted into ASCII characters by the CHR$ function. Notice also that since the integer format requires four locations for each character, the locations 260-263 and 264-267 correspond to upper-case A and B respectively (which probably explains the variable names). Now that "ltr.a$" and "ltr.b$" contain the definitions for the two characters, we'll load the font into the character generator, turn on 40 column mode, clear the screen, and print seve10 FOR i=1 TO 4 715 READ a%,b%,c%,d%,e%,f% 720 h1$=HEX$(a%):h2$=HEX$(b%):b1$=HEX$(c%):b2$=HEX$(d%) 725 t1$=HEX$(e%):t2$=HEX$(f%) 730 head1$=head1$+CHR$(TEN(MID$(h1$,1,2)))+CHR$(TEN(MID$(h1$,3,2))) 735 head2$=head2$+CHR$(TEN(MID$(t up screen After the initialization in lines 10-70, three subroutines are called to set things up for the animation to follow. They look like this (in order of use): 700 RESTORE 705 head1$="":head2$="":body1$="":body2$="":tail1$="":tail2$="" 7 q$=CHR$(34):array$="a%" 40 fg$=CHR$(19):bg$=CHR$(20) 50 mblue$=CHR$(6):white$=CHR$(15) 60 bw$=fg$+mblue$+bg$+white$ 70 text40$=CHR$(16)+CHR$(1) 80 GOSUB 700:REM get font 90 GOSUB 800:REM load up the bugs 100 GOSUB 600:REM selittle critters move. It is similar in structure to the previous program, with a more general purpose design, and has some similarities to the game program from last time: 10 DIM a%(511) 20 INVOKE"/basic/download.inv","/basic/request.inv" 30 opulate our game. The character definitions were created by the font editor from a few episodes back, or could be created with any font-editing program. The next program takes those character definitions and demonstrates how they can be used to make our answered by the next program. Remember, just because we changed one letter to another doesn't mean that's the only use of the principle. Last time we looked at redefining characters (we used control characters 21 through 26) to make little creatures to perent definition, since the change is in the character generator, not in the screen memory itself. Some Relevance Rears its Ugly Head What, you ask, does this have to do with "Bug-Mania" and character set animation? Good question, and one about to be TEXT:HOME 530 nam$=q$+"/basic/standard"+q$ 540 PERFORM getfont(@nam$,@array$):PERFORM loadfont(@array$) 550 PRINT CHR$(15); 560 END Well, there you have it. The routine above could just as easily change every character on the screen to a diff's turn to B's and back. Holding down a fast repeating key will give you an idea of just how fast these changes can take place. Pressing ESCape will allow the routine to clean up and end: 500 REM Restore Screen 510 PRINT CHR$(22);CHR$(14) 520 mally an upper-case A, is being defined in "ctrlist1$" as a "B" and in "ctrlist2$" as an "A". Lines 150-180 do the character switching, with "GET" statements in-between to allow you to see what's going on. By slowly pressing any key, you can watch the Aen the character number, followed by the character definition. If you load more than one character, the first value changes, and then each character definition in the string is preceeded with its character number. In this case, character 65, which is norame$ 180 GET a$:IF ASC(a$)<>27 THEN 150 In line 110, we define the name of the device driver to be called, and then lines 120 and 130 set up the parameter string for the control call. Notice that the format is the number of characters to be loaded, thoad that was mention before: 110 name$=".console" 120 ctrlist1$=CHR$(1)+CHR$(65)+ltr.b$ 130 ctrlist2$=CHR$(1)+CHR$(65)+ltr.a$ 150 PERFORM control(%17,@ctrlist1$)name$ 160 GET a$:IF ASC(a$)=27 THEN 500 170 PERFORM control(%17,@ctrlist2$)nral lines of A's and B's on the screen, like this: 90 PERFORM loadfont(@array$) 95 PRINT text40$:HOME 100 FOR i=1 TO 10:PRINT"ABABABABABABABABABABAB":NEXT i Next, we'll change those characters on the screen by using the partial character downlh2$,1,2)))+CHR$(TEN(MID$(h2$,3,2))) 740 body1$=body1$+CHR$(TEN(MID$(b1$,1,2)))+CHR$(TEN(MID$(b1$,3,2))) 745 body2$=body2$+CHR$(TEN(MID$(b2$,1,2)))+CHR$(TEN(MID$(b2$,3,2))) 750 tail1$=tail1$+CHR$(TEN(MID$(t1$,1,2)))+CHR$(TEN(MID$(t1$,3,2))) 755 tail2$=tail2$+CHR$(TEN(MID$(t2$,1,2)))+CHR$(TEN(MID$(t2$,3,2))) 760 NEXT i 765 RETURN 780 DATA 7215,7215,14462,14462,0,0 785 DATA 32545,31555,27519,22399,1090,580 790 DATA 838,16156,32546,32546,16932,26640 795 DATA 15360,0,@ctrlist2$)name$:FOR i=1 TO 10*pause:NEXT 170 GOTO 150 This section is also similar to the last program, except this time we load three characters at a time. Also, instead of requesting input between each character switch to slow the display changestrlist1$=CHR$(3)+CHR$(23)+head1$+CHR$(22)+body1$+CHR$(21)+tail1$ 130 ctrlist2$=CHR$(3)+CHR$(23)+head2$+CHR$(22)+body2$+CHR$(21)+tail2$ 140 ON KBD GOTO 200 150 PERFORM control(%17,@ctrlist1$)name$:FOR i=1 TO 10*pause:NEXT 160 PERFORM control(%17prints lots of bug-filled strings: 600 PRINT text40$;bw$;:HOME 610 PERFORM loadfont(@array$) 620 FOR i=1 TO 11 630 PRINT m$ 640 NEXT i 650 RETURN Now that the setup is done, it's on with the show: 110 name$=".console" 120 cthan 127 are used in order to map into the printable control character space. Characters 149-151 correspond to 21-23 in the standard ASCII set and are the same as used in last month's game. Now on to the subroutine at 600, which sets up the screen and 40:SUB$(m$,i,1)=char$(VAL(MID$(m$,i,1))):NEXT i 830 RETURN The routine above uses a technique borrowed from last article to create "m$" with the appropriate characters for the head, body and tail of the creatures. Notice that character values greater l the character download capability is, we'll build strings of creature characters to populate the screen: 800 char$(0)=" ":char$(1)=CHR$(149):char$(2)=CHR$(150):char$(3)=CHR$(151) 810 m$=".23...123.1223..13.123.3.23...123.1223.." 820 FOR i=1 TO racters from last month's game set, if you have defined that font. By changing the parameters on the FOR-NEXT loops, and in the build routine below, you could use any set of characters from any font. To simplify the screen display, and to show how powerfu i=96 TO 99 758 tl$=HEX$(a%(i)) 760 tail2$=tail2$+CHR$(TEN(MID$(tl$,1,2)))+CHR$(TEN(MID$(tl$,3,2))) 762 NEXT i 764 RETURN That seems like a lot of repeating, and it is, mostly for clarity. As set up, the lines above will extract the cha=100 TO 103 744 bd$=HEX$(a%(i)) 746 body2$=body2$+CHR$(TEN(MID$(bd$,1,2)))+CHR$(TEN(MID$(bd$,3,2))) 748 FOR i=84 TO 87 750 tl$=HEX$(a%(i)) 752 tail1$=tail1$+CHR$(TEN(MID$(tl$,1,2)))+CHR$(TEN(MID$(tl$,3,2))) 754 NEXT i 756 FOR hd$=HEX$(a%(i)) 730 head2$=head2$+CHR$(TEN(MID$(hd$,1,2)))+CHR$(TEN(MID$(hd$,3,2))) 732 NEXT i 734 FOR i=88 TO 91 736 bd$=HEX$(a%(i)) 738 body1$=body1$+CHR$(TEN(MID$(bd$,1,2)))+CHR$(TEN(MID$(bd$,3,2))) 740 NEXT i 742 FOR ietfont(@name$,@array$) 716 head1$="":head2$="":body1$="":body2$="":tail1$="":tail2$="" 718 FOR i=92 TO 95 720 hd$=HEX$(a%(i)) 722 head1$=head1$+CHR$(TEN(MID$(hd$,1,2)))+CHR$(TEN(MID$(hd$,3,2))) 724 NEXT i 726 FOR i=104 TO 107 728 editor, or a similar one which produces system font files, you could use the "Bug-mania" font from Article 18, substituting the following lines for lines 700-795 above: 700 INPUT"Name of font file: ";flname$ 702 name$=q$+flname$+q$ 714 PERFORM gut, in the immortal words of many a programmer, "trust me". These values define our tiny creature's head, body and tail, and were, in fact, extracted from a font created by the font editor from Article 17. In the event you have a working version of that ,8806,4369,6144,0 The routine above uses some of the techniques from the last program defining the characters, except that this time we are reading the font definition from the data statements in lines 780-795. These numbers may look like gibberish, b down, FOR-NEXT loops are introduced, with a variable speed depending on the value of "pause". Exits and speed changes are taken by pressing keys which use the ON KBD routine in line 200: 200 OFF KBD 210 IF KBD=27 THEN 500 220 IF KBD>47 AND KBD<58 THEN pause= KBD-48 230 ON KBD GOTO 200 240 RETURN Notice above that if ESCape (ASCII 27) is pressed, a jump is taken to line 500, where the program ends. If a number is pressed, then the pause factor is set to that numeric value. This allows yo With the exception of array dimension statements for the seven versions of the head, and the fourteen versions of the control list necessary to define the different versions of the head, it's the same as in the last program. As in the description of thaR$(6):white$=CHR$(15) 60 bw$=fg$+mblue$+bg$+white$ 70 text40$=CHR$(16)+CHR$(1) 80 GOSUB 700:REM get the head definitions 90 GOSUB 800:REM load the print line 100 GOSUB 600:REM set up screen If the program above looks familiar, it should. next character cell. All of which leads us to the following program: 10 DIM a%(511),ctrlist$(13),head1$(6),head2$(6) 20 INVOKE"/basic/download.inv","/basic/request.inv" 30 q$=CHR$(34):array$="a%" 40 fg$=CHR$(19):bg$=CHR$(20) 50 mblue$=CHppear to move smoothly from one cell to another. Since a character cell is seven dots wide, this implies that to create smooth horizontal motion will require seven different definitions of the same character, each one moved over one row of pixels into thetiple character definitions, and therein lies the solution to our dilemma. If we could create a definition of an object in all the phases of moving from one character cell to another, and could download these redefinitions rapidly, then the object would ahat can open up a whole new bag of tricks, but we're not finished with what text mode graphics can do for us yet. It Ain't the Mode, it's the Motion The text mode character sets are so fast that a whole new possibility exists to make motion out of mulaphics screen instead of the text screen that we have been using. Since you can draw any character at any dot location on the graphics screen, it's just a matter of repositioning and printing. Later on, and especially in the next article, we'll see how ters appear to jerk from place to place, because there are only 40 places to draw them. But are we doomed to jerky animation? Not the MicroKids! One obvious solution to the dilemma, and one which will be discussed in a moment, lies in using the hi-res grthe screen? That looked ok, but it suffered from one fact of life about printing characters, that is, there are only a limited number of horizontal locations where you can print them. In the case of the 40 column mode that we have been using, the charact what we're after. The really interesting stuff is to use the character redefinition capability to produce smooth motion. Remember in the last article where we got animation by printing several different versions of the characters in different places on mended for starters) will demonstrate that this technique can produce some really fast in-place animation. With "pause" equal to zero, the critters will run in place so fast that you can hardly see their little legs move. However, running in place is notets all console options back to normal. While this is not necessary in this case, it is good practice, and will be required in some later programs. That's All Fine, but was it Good for You? Running the program above (the DATA statement version is recom$(22);CHR$(14); 520 TEXT:HOME 530 nam$=q$+"/basic/standard"+q$ 540 PERFORM getfont(@nam$,@array$):PERFORM loadfont(@array$) 550 PRINT CHR$(15); 560 END The only noticeable change in the routine above is that the 'CHR$(21);"="' in line 500 su to see the speeds possible with this technique, while the program is running. Obviously, the routine could do lots of other interesting things. The cleanup routine, very similar to last time, looks like this: 500 PRINT CHR$(21);"=" 510 PRINT CHRt program, let's take the subroutines in order: 700 RESTORE 710 FOR i=0 TO 6 715 head1$(i)="":head2$(i)="" 720 FOR j=0 TO 3 725 READ a%:h$=HEX$(a%) 730 head1$(i)=head1$(i)+CHR$(TEN(MID$(h$,1,2)))+CHR$(TEN(MID$(h$,3,2))) 735 NEXT j 740 FOR j=0 TO 3 745 READ a%:h$=HEX$(a%) 750 head2$(i)=head2$(i)+CHR$(TEN(MID$(h$,1,2)))+CHR$(TEN(MID$(h$,3,2))) 755 NEXT j 760 NEXT i 765 RETURN 770 DATA 7215,32545,838,15360,0,0,0,0 772 DATA 14430,3231. The second seven (in lines 130-140) show how the head looks moving from 1 to 0. Recall that since the screen lineup is 010101... that steady cycling through the definitions will create the desired motion. Line 150 and 155 accomplish this, endlessly rGOTO 200 150 FOR i=0 TO 13:PERFORM control(%17,@ctrlist$(i))name$:NEXT 155 GOTO 150 This time we create a series of control strings for efficiency. The first seven definitions in "ctrlist$" describe how the head moves from character 0 to character ttention: 110 name$=".console" 115 FOR i=0 TO 6 120 ctrlist$(i)=CHR$(2)+CHR$(0)+head1$(i)+CHR$(1)+head2$(i) 125 NEXT i 130 FOR i=7 TO 13 135 ctrlist$(i)=CHR$(2)+CHR$(0)+head2$(i-7)+CHR$(1)+head1$(i-7) 140 NEXT i 145 ON KBD creen. This time we've chosen to fill nearly the whole screen up with characters, to wit: 600 PRINT text40$;bw$ 610 HOME:PRINT:PRINT 620 FOR i=1 TO 21 630 PRINT m$; 640 NEXT i 650 RETURN Ok, now to make all these little heads pay aters, that will be handled by successively redefining the two on the screen. Note also that we fill up "m$" completely, because we want smooth motion from one side of the screen to the other. Next comes the routine to put our character strings on the s1212121212" 820 FOR i=1 TO 40:SUB$(m$,i,1)=char$(VAL(MID$(m$,i,1))):NEXT i 830 RETURN Notice that this time we use ASCII 0 and 1 as our characters to redefine (converted to 128 and 129 to make them displayable). We don't need seven different characin the previous program. Next, the subroutine at 800-830 builds the character string in a similar fashion to last program, with some notable exceptions: 800 char$(0)=" ":char$(1)=CHR$(128):char$(2)=CHR$(129) 810 m$="121212121212121212121212121212 as you might have guessed, these numbers came from defining the characters with the font editor, and then printing out the results. Changing the program to accomodate font editor output directly would be done in a similar way to the alternate subroutine the head shifted over one dot column into the adjacent cell. Since there is already a definition for the head completely in a cell, there is no need for an eighth definition, we can just switch the character definitions around. More on that later. Also, next row of data (line 772) describes what the head looks like when it is shifted one dot over in the first cell, and the second cell picks up the column of dots from the rightmost column of the first cell. The definition proceeds, each row representing his is loaded by 720-735 into the first "head1$" definition. The next four numbers, all zeros in this case, make up the definition of the adjacent cell. This is logical, since the head starts in the first cell completely, with the second cell blank. The, you'll notice that the first four elements of line 770 in this program match the data in the first column in the other program. That's because 7215, 32545, 838, and 15360 are the four elements of the font definition which make up the creature's head. T144,291,7680 The code in 700-765 above looks simpler (certainly shorter) than last program, but notice that there is lots more data. Simply put, each line of data defines two adjacent character cells. If you look back at the data in the previous program22,1548,30720,0,256,1,0 774 DATA 28732,31748,3096,28672,1,769,2,256 776 DATA 24696,30728,6192,24576,258,1794,4,768 778 DATA 16496,28688,12384,16384,773,3844,8,1792 780 DATA 96,24608,24640,0,1803,7944,17,3840 782 DATA 64,16448,16384,0,3607,16epeating the whole sequence. The ON KBD routine is simpler this time, and just gives us a way out: 200 OFF KBD 210 IF KBD=27 THEN 500 220 ON KBD GOTO 200 230 RETURN The cleanup routine at 500 is identical to the one in the last program. Just copy it and you'll exit to the normal world properly with the ESC character. At Long Last, Bug When you run this, the effect is somewhat amazing. With a simple Basic program, you're creating smooth amimation which takes quite a bit of assembly langr(%9) 55 PERFORM viewport(%0,%6,%0,%191):PERFORM fillport 60 PERFORM viewport(%133,%139,%0,%191):PERFORM fillport 65 PERFORM fillcolor(%4) 70 PERFORM viewport(%0,%139,%0,%191) 75 PERFORM grafixon 80 FOR j=7 TO-77 STEP-1 85 PERFORM mo" ** **** ** **** *** * **** ** *****" 25 PERFORM initgrafix 30 PERFORM grafixmode(%3,%1) 35 PERFORM pencolor(%13) 40 PERFORM fillcolor(%4):PERFORM fillport 45 PERFORM setctab(%4,%9,%9):PERFORM setctab(%13,%9,%9) 50 PERFORM fillcolo little program will give a clue to some of the graphic's drivers special capabilities, which will be used fully in the next exciting episode of this long-winded serial. Try the following: 10 INVOKE"/basic/bgraf.inv" 15 OPEN#1,".grafix" 20 m$= This allows you to print special characters like the bug's head onto the graphics screen, just as you would any other character. If positioning was the only virtue of the graphics driver, then it would be not nearly as useful as we would want. The nextWatch this closely, its a clue to what's happening in the graphics driver. Another thing is interesting and it's worth experimenting with. Try changing the text character set before opening the ".grafix" driver, using the techniques previously described. article. First, notice that we can print off the screen without any apparent problem, and without wrapping onto the next line. Second, notice that the display seems to move faster as less and less of the string is actually printed in the display area. TEXT 115 END This just prints the string "m$" starting at each successive location on the high-res screen, in this case the 140X192 16 color mode. One or two things should be noted here, which will become more important later, expecially in the next pencolor(%13) 40 PERFORM fillport 45 PERFORM grafixon 50 FOR i=0 TO 139 55 PERFORM moveto(%i,%180):PRINT#1;m$ 60 NEXT i 65 GET a$:IF ASC(a$)<>27 THEN 50 100 PERFORM release:PERFORM release:PERFORM release 105 CLOSE:INVOKE 110 nothing like a trivial program to demonstrate that fact: 10 INVOKE"/basic/bgraf.inv" 15 OPEN#1,".grafix" 20 m$=" ** **** ** **** *** * **** ** ***" 25 PERFORM initgrafix 30 PERFORM grafixmode(%3,%1) 35 PERFORM fillcolor(%4):PERFORMlast a lifetime, but since it's only one short month until next month's article, we had best move on to the promised treatment of the high-resolution graphics mode. As was mentioned previously, smooth motion on the high-res screen is trivial, and there's le. By creating multiple definitions of these characters, both in place and in motion, you can repeat that display yourself, using the principles in this article. RAMbling Onward As you might guess, the paragraph above contains enough suggestions to high-res screen. Think again, bucko! That demo uses the save character set redefinition techniques that we've just been discussing. If you are patient enough, you might create the horse by defining all the characters, each a small piece of the big puzzunning horse demo on the System Demo disk? If you haven't seen it, take a moment to run the demo that comes with each Apple /// and select the "horse" section. You will see magnificent full color animation, that you probably always thought was done on theuage on an Apple ][, IBM PC, etc. In fact, even the best assembly programmers would be hard-pressed to create smooth motion over such a large area of the screen. But wait, you say. You've seen smooth animation on the Apple /// before. What about that rveto(%j,%180):PRINT#1;m$ 90 NEXT j 95 GET a$:IF ASC(a$)<>27 THEN 80 100 PERFORM release:PERFORM release:PERFORM release 105 CLOSE:INVOKE 110 TEXT 115 END Getting Your (Color) Priorities Straight Looks pretty much like the last one, right? Not right. Notice that our primary colors are 4 and 13, the fillcolor and pencolor respectively. Notice also the color priority definition in line 45. This says that anytime color 4 or color 13 are printed over color 9 (which is the color of two b4:s%=16:z%=0 60 x%(8)=-3:x%(21)=3:y%(11)=3:y%(10)=-3 65 i=70:j=90 70 PERFORM moveto(%i,%j) 75 IF r%=0 THEN r%=16:ELSE r%=0 80 PERFORM drawimage(@shape%(0,0),%f%,%r%,%z%,%s%,%s%) 85 GET a$:a=ASC(a$) 90 IF a<>27 THEN i=i+x%(a):j=j+y%(a):ic/bgraf.inv" 15 OPEN#1,".grafix" 20 GOSUB 1000 25 PERFORM initgrafix 30 PERFORM grafixmode(%3,%1) 35 PERFORM fillcolor(%4):PERFORM pencolor(%13) 40 PERFORM fillport 45 PERFORM viewport(%0,%139,%0,%191) 50 PERFORM grafixon 55 f%=FORM setctab(%brown%,%white%,%white%) 1230 PERFORM setctab(%grey%,%green%,%green%) 1240 PERFORM setctab(%grey%,%white%,%white%) 1250 PERFORM setctab(%yellow%,%white%,%white%) 1260 RETURN 5 DIM shape%(1,15),x%(127),y%(127) 10 INVOKE"/bas PERFORM setctab(%dgreen%,%orange%,%orange%) 1180 PERFORM setctab(%dgreen%,%green%,%green%) 1190 PERFORM setctab(%dgreen%,%white%,%white%) 1200 PERFORM setctab(%brown%,%orange%,%orange%) 1210 PERFORM setctab(%brown%,%green%,%green%) 1220 PERRFORM lineto(%0,%96) 450 NEXT j 460 NEXT i 500 GET a$:IF ASC(a$)<>27 THEN TEXT:GOTO 255 510 TEXT 520 INVOKE:CLOSE 530 PERFORM release:PERFORM release:PERFORM release 540 END 1160 PERFORM setctab(%dgreen%,%blue%,%blue%) 1170 RFORM fillcolor(%white%):PERFORM fillport 400 PERFORM viewport(%0,%139,%0,%192) 405 FOR i=1 TO 4 410 FOR j=1 TO 10 415 horiz=(i-1)*45+j*4 420 PERFORM moveto(%140,%horiz) 430 PERFORM pencolor(%vector(i)) 440 PEORM fil lport 320 PERFORM viewport(%52,%65,%40,%170):PERFORM fillcolor(%orange%):PERFORM f illport 330 PERFORM viewport(%77,%92,%35,%175):PERFORM fillcolor(%green%):PERFORM fi llport 340 PERFORM viewport(%110,%120,%20,%170):PE<0 OR a>15 THEN 510 265 PERFORM grafixon 270 PERFORM fillcolor(%a):PERFORM fillport 300 PERFORM viewport(%20,%30,%40,%170):PERFORM fillcolor(%black%):PERFORM fi llport 310 PERFORM viewport(%35,%40,%30,%160):PERFORM fillcolor(%blue%):PERFERFORM setctab(%brown%,%white%,%white%) 230 PERFORM setctab(%grey%,%green%,%green%) 240 PERFORM setctab(%grey%,%white%,%white%) 250 PERFORM setctab(%yellow%,%white%,%white%) 255 INPUT"Background color number: ";a$ 260 a=VAL(a$):IF a$="" OR a 170 PERFORM setctab(%dgreen%,%orange%,%orange%) 180 PERFORM setctab(%dgreen%,%green%,%green%) 190 PERFORM setctab(%dgreen%,%white%,%white%) 200 PERFORM setctab(%brown%,%orange%,%orange%) 210 PERFORM setctab(%brown%,%green%,%green%) 220 Pange%=9:green%=12:white%=15:dgreen%=4:brown%=8:grey%= 10:yellow%=13 130 PERFORM grafixmode(%3,%1) 140 PERFORM initgrafix 150 vector(1)=dgreen%:vector(2)=brown%:vector(3)=grey%:vector(4)=yellow% 160 PERFORM setctab(%dgreen%,%blue%,%blue%)es. Until then, remember that a pixel a day keeps boredom away, which gives you 107,520 days to enjoy your Apple ///! 50 REM 7, 11 and 14 are best background colors 100 OPEN#1,".grafix" 110 INVOKE"/basic/bgraf.inv" 120 black%=0:blue%=6:orry powerful feature of the Apple /// graphics driver, one which is exploited very little by programmers. Next time we will work this feature to death, and in the process do things which would challenge the best of the high-res jocks on less capable machinorder strips that are set up at each edge of the screen) that the result should remain color 9. Run the program and see how this works. You should also notice that this time the print string runs backwards, not forwards. The color priority table is a veGOTO 70 100 PERFORM release:PERFORM release:PERFORM release 105 CLOSE:INVOKE 110 TEXT 115 END 1000 FOR j=0 TO 15:FOR i=0 TO 1:READ shape%(i,j):NEXT:NEXT 1010 RETURN 2000 DATA 0,0 2005 DATA 0,0 2010 DATA 0,0 2015 DATA 0,1984 2020 DATA 1984,2080 2025 DATA 2080,4752 2030 DATA 4752,4112 2035 DATA 4112,5008 2040 DATA 5008,2080 2045 DATA 2080,1984 2050 DATA 1984,2336 2055 DATA 2976,2720 2060 DATA 1344,4752 2065 DATA 0,0 a%(511))".D1/download.inv",".D1/request.inv"q$=34):array$="a%"(fg$=19):bg$=20)2mblue$=6):white$=15)<bw$=fg$+mblue$+bg$+white$Ftext40$=16)+1)P700: get font Z800: load up the bugs d600: set up screen ):OFF ERR:CLOSE#3 1080 IF ret%<>256 THEN error=2:RETURN:REM Shape definition is invalid 1090 error=0:RETURN:REM Shape loaded %":OPEN#3,file$ 1020 IF TYP(3)=1 THEN READ#3;filtyp,ch,cw,sl:IF filtyp=1 THEN 1070 1030 OFF ERR:CLOSE#3 1040 IF TYP(3)=0 THEN DELETE file$ 1050 error=1:REM Not a shape file 1060 RETURN 1070 READ#3,1:PERFORM filread(%3,@array$,%256,@ret% PERFORM drawimage(@tshape%(0,0),%s%,%r%,%z%,%s%,%t%) 160 NEXT k 200 GET a$:IF ASC(a$)<>27 THEN 105 300 PERFORM release:PERFORM release:PERFORM release 310 CLOSE:INVOKE 320 TEXT 330 END 1000 ON ERR GOTO 1030 1010 array$="shape+85 125 r%=t%+s%*(r%=t%) 130 PERFORM moveto(%k+28,%j) 135 PERFORM drawimage(@tshape%(0,0),%s%,%r%,%z%,%s%,%t%) 140 PERFORM moveto(%k+14,%l) 145 PERFORM drawimage(@shape%(0,0),%s%,%r%,%z%,%s%,%s%) 150 PERFORM moveto(%k,%m) 155%7):PERFORM fillport 55 PERFORM viewport(%40,%100,%15,%130) 60 PERFORM fillcolor(%13):PERFORM fillport 65 PERFORM grafixon 100 s%=16:t%=32:z%=0 105 FOR k=0 TO 100 110 j=COS(k/5+2)*53+88 115 l=SIN(k/10)*30+58 120 m=SIN(k/10)*70basic/request.inv" 20 OPEN#1,".grafix" 25 file$="next.shape":GOSUB 1000 30 FOR j=0 TO 15:FOR i=0 TO 7:tshape%(i,j+8)=shape%(i,j):NEXT:NEXT 35 PERFORM initgrafix 40 PERFORM grafixmode(%3,%1) 45 PERFORM pencolor(%4) 50 PERFORM fillcolor( DATA 4112,5008 2040 DATA 5008,2080 2045 DATA 2080,1984 2050 DATA 1984,2336 2055 DATA 2976,2720 2060 DATA 1344,4752 2065 DATA 0,0 2070 DATA 0,0 2075 DATA 0,0 10 DIM shape%(7,15),tshape%(7,31) 15 INVOKE"/basic/bgraf.inv","/shape%(i,j):NEXT:NEXT 1010 FOR j=0 TO 15:FOR i=0 TO 1:zshape%(i,j+8)=mshape%(i,j):NEXT:NEXT 1020 RETURN 2000 DATA 0,0 2005 DATA 0,0 2010 DATA 0,0 2015 DATA 0,1984 2020 DATA 1984,2080 2025 DATA 2080,4752 2030 DATA 4752,4112 2035 155 PERFORM drawimage(@zshape%(0,0),%f%,%r%,%z%,%s%,%t%) 160 NEXT k 200 GET a$:IF ASC(a$)<>27 THEN 105 300 PERFORM release:PERFORM release:PERFORM release 310 CLOSE:INVOKE 320 TEXT 330 END 1000 FOR j=0 TO 15:FOR i=0 TO 1:READ m/10)*70+85 125 r%=s%*(r%=z%) 130 PERFORM moveto(%k+28,%j) 135 PERFORM drawimage(@zshape%(0,0),%f%,%r%,%z%,%s%,%t%) 140 PERFORM moveto(%k+14,%l) 145 PERFORM drawimage(@mshape%(0,0),%f%,%r%,%z%,%s%,%s%) 150 PERFORM moveto(%k,%m)r(%7):PERFORM fillport 55 PERFORM viewport(%40,%100,%15,%130) 60 PERFORM fillcolor(%13):PERFORM fillport 65 PERFORM grafixon 100 s%=16:t%=32:z%=0:f%=4 105 FOR k=0 TO 100 110 j=COS(k/5+2)*53+88 115 l=SIN(k/10)*30+58 120 m=SIN(k 2070 DATA 0,0 2075 DATA 0,0 10 DIM mshape%(1,15),zshape%(1,31) 15 INVOKE"/basic/bgraf.inv" 20 OPEN#1,".grafix" 25 GOSUB 1000 35 PERFORM initgrafix 40 PERFORM grafixmode(%3,%1) 45 PERFORM pencolor(%4) 50 PERFORM fillcolonname$=".console" x200 i=060ctrlist1$=2)+0)+head1$(i)+1)+head2$(i)2control(%17,@ctrlist1$)name$:j=110*pause:i i=060ctrlist1$=2)+0)+head2$(i)+1)+head1$(i)2control(%17,@ctrlist1$)name$:j=110*pause:?-2 7, 11 and 14 are best background colorsd#1,".grafix"n"/profile/basic/bgraf.inv"Yxblack%=0:blue%=6:orange%=9:green%=12:white%=15:dgreen%=4:brown%=8:grey%=10:yellow%=13grafixmode(%3,%1)initgrafixHvector(1)=dgreen%:vector(2)=brow,76800 char$(0)=" ":char$(1)=128):char$(2)=129)1*m$="1212121212121212121212121212121212121212",4i=140:m$,i,1)=char$(m$,i,1))):i>,32546,16932,266402,26640,32546,16932,2664015360,0,0,0,0& 14430,32322,1548,30720,0,256,1,0( 28732,31748,3096,28672,1,769,2,256+ 24696,30728,6192,24576,258,1794,4,768-  16496,28688,12384,16384,773,3844,8,1792(  96,24608,24640,0,1803,7944,17,3840* 64,16448,16384,0,3607,16144,291 i=06head1$(i)="":head2$(i)="" j=03a%:h$=a%)7head1$(i)=head1$(i)+h$,1,2)))+h$,3,2)))j j=03a%:h$=a%)7head2$(i)=head2$(i)+h$,1,2)))+h$,3,2)))ji" 7215,32545,838,name$:150 Process keystrokes=27500 20021);"="22);14);:nam$=q$+".D1/standard"+q$.getfont(@nam$,@array$):loadfont(@array$) &15);0Xtext40$;bw$ b:: li=121vm$;i: load the print lined600: set up screen nname$=".console" si=062xctrlist$(i)=2)+0)+head1$(i)+1)+head2$(i)}i i=7136ctrlist$(i)=2)+0)+head2$(i-7)+1)+head1$(i-7)i 200.i=013:control(%17,@ctrlist$(i))- a%(511),ctrlist$(13),head1$(6),head2$(6))".D1/download.inv",".D1/request.inv"q$=34):array$="a%"(fg$=19):bg$=20)2mblue$=6):white$=15)<bw$=fg$+mblue$+bg$+white$Ftext40$=16)+1)#P700: get the head definitionsZ800,3607,16144,291,76800 char$(0)=" ":char$(1)=128):char$(2)=129)1*m$="1212121212121212121212121212121212121212",4i=140:m$,i,1)=char$(m$,i,1))):i>",32546,16932,26640,32546,16932,266407215,32545,838,15360,0,0,0,0& 14430,32322,1548,30720,0,256,1,0( 28732,31748,3096,28672,1,769,2,256+ 24696,30728,6192,24576,258,1794,4,768-  16496,28688,12384,16384,773,3844,8,1792(  96,24608,24640,0,1803,7944,17,3840* 64,16448,16384,0vm$i i=06head1$(i)="":head2$(i)="" j=03a%:h$=a%)7head1$(i)=head1$(i)+h$,1,2)))+h$,3,2)))j j=03a%:h$=a%)7head2$(i)=head2$(i)+h$,1,2)))+h$,3,2)))ji" i130=27500>47<58pause=-48 20021);"="22);14);:(nam$=q$+"/profile/basic/standard"+q$.getfont(@nam$,@array$):loadfont(@array$) &15);0Xtext40$;bw$ b:: li=111n%:vector(3)=grey%:vector(4)=yellow% 1000#"Background color number: ";a$"a=a$):a$=""a<0a>15510 grafixonfillcolor(%a):fillport,viewport(%20,%30,%40,%170)!6fillcolor(%black%):fillport@viewport(%35,%40,%30,%160) Jf