-IMPORTANT NOTE---------------------------------------------------------------- NOTE: Issues 1-8 of the Basix Fanzine were edited by Peter Cooper. Issues 9-13 of the Basix Fanzine were edited by Alex Warren. The new editor of the Basix Fanzine is David Groulx and the addresses for the fanzine are: ARTICLES: Basix_Fanzine@yahoo.com OTHER ENQUIRIES ETC.: Basix_Fanzine@yahoo.com WWW ADDRESS: http://www.come.to/basixfanzine Please use these addresses in place of the out-of-date addresses in the Fanzine below. David Groulx April 1999 ------------------------------------------------------------------------------- The Basix Fanzine - TEXT VERSION issue 12 · september/october 1998 email: basix@dewarr.globalnet.co.uk www: http://come.to/basixfanzine -------------------------------------------------------------------------------- [This is the text version of The Basix Fanzine, issue 12. It is a copy-and-paste-over of the HTML version and as a result may contain a few formatting errors] Welcome to issue 12 of the Basix Fanzine! You'll notice that this is the "September/October 1998" issue - I'm trying to release this thing more regularly, and at first I'll be aiming for a bi-monthly issue. It would be nice if I could release it monthly, but I'm not sure if I'll ever have the time or get enough submissions for that to be possible. Anyway, on with the show. In this issue: improve your programming skills... include data in an EXE file... encrypt files... and relieve boredom! -------------------------------------------------------------------------------- Levels are represented in bold by B, I or A for Beginner, Intermediate and Advanced respectively, or a combination. They aren't clear-cut definitions though, so you might find something useful labelled (B) even though you've been programming for 10 years, for example. Unless otherwise stated, the articles apply to all major breeds of BASIC. Most of these links point to parts of this HTML document, although some may point to other HTML files in the Basix Fanzine directory. Each article has a link back to this contents section to save you the bother of scrolling back. news COMP.LANG.BASIC.POWERBASIC PASSES The proposed comp.lang.basic.powerbasic newsgroup is a reality! NEW ABC MIRROR The ABC packets now have a mirror in the UK. Which is nice. articles GRAPHICS IN QBASIC TUTORIAL (PART 3) (I/A) "Hacker" aka Damian Nikodem rounds off his graphics series with a look at randomic algorithms. INTERMEDIATE PROGRAMMING TIPS (PART 1) (I) Alex Warren takes a look at variable types and screen-page swapping. INCLUDING FILES IN EXEs (I/A) Ollie Cook demonstrates a method of including data files within your EXE file. FONTS: AN ALTERNATIVE GRAPHIC Regular contributor RudeJohn ponders upon the subject of fonts. TEN ODD MOMENTS RudeJohn's amazing list of "things to do", for bored programmers. BACKUS-NAUR FORM (A) RudeJohn presents an introduction to the Backus-Naur Form. your programs DETECTING THE PARALLEL PORT by Juan F. Miguez BINARY FILE ENCRYPTION by Daniel Bolger CONTROL+BREAK DISABLER by Daniel Bolger "A SCREENSAVER TYPE THING" by Mike Anderson letters PROGRAMS, MIDI & INP from Daniel Bolger internet resources final words LAST WORDS, THANKS ETC. NEXT ISSUE (The "From the Newsgroups" section is on holiday...) ******************************************************************************** NEWS the latest news in the BASIC world *** COMP.LANG.BASIC.POWERBASIC PASSES The proposed comp.lang.basic.powerbasic newsgroup passed its vote, with 149 "yes" votes to 14 "no" votes. 100 more "yes" than "no" votes were required, and two thirds had to be in favour in order for the group to be created - and that has happened, so comp.lang.basic.powerbasic should be hitting your news server soon! *** NEW ABC MIRROR There is a new mirror for the ABC packets in the UK, available at http://www.cvnet.co.uk/o.cook/abc. The site also includes several useful links so is worth a look anyway, even if you don't need the packets. ******************************************************************************** Got a BASIC news article? pleeease? Opening a website? Want to announce a new product that will benefit BASIC programmers? Want to reach hundreds of readers for free? Then send your press release to basix@dewarr.globalnet.co.uk NOW! [The editor reserves the right to edit or omit articles recieved for publication - if you want an advert rather than a news article, read on.] ******************************************************************************** ARTICLES enhance your programming - this is the place to learn BASIC tips, techniques and tricks! *** GRAPHICS IN QBASIC TUTORIAL (PART 3), by "Hacker" aka Damian Nikodem · Hacker@alphalink.com.au Intro : Today I will cover RANDOMIC ALGORITHMS. You will probably be asking yourself what are they and how will they improve the graphics in my programs. Well randomic algorythms add a twist of reality to your graphics. Take a look around you is everything around you in total order is there NO light shining off ANYTHING near you. If you notaice nearly everything has a random element. So this is where I will base my tutorial on today. Grass Routine: Now lets just say that your writing a RPG and you have to write a graphics routine. It most likeley looks kinda like this (asuming you are doing a 15x15 tileset) 'Start CODE SCREEN 13 LINE (1,1)-(15,15),2 , BF 'END CODE Well try this little program instead: 'Start CODE SCREEN 13 RANDOMIZE TIMER FOR x = 1 TO 15 FOR y = 1 TO 15 z = INT(RND * 2) + 1 IF z = 2 THEN z = 10 IF z = 1 THEN z = 2 PSET (x, y), z NEXT y NEXT x 'END code Does that look a bit better? It should. But its still missing something isnt it, it dosent have enough colors. Because we are using VGA mode 13h(Screen 13) we have 255 colors to play with theres bound to be at least 1 GREEN! WAIT. there is also dirt on the ground so we have to add BROWN and if you look almost always there is about 2 browns before a green so here is a small EDIT of the program above: 'Start CODE SCREEN 13 RANDOMIZE TIMER FOR x = 1 TO 15 FOR y = 1 TO 15 z2 = INT(RND * 8) + 1 z = z2 + 186 PSET (x, y), z NEXT y NEXT x 'End CODE Now do you see the benifits of randomized graphics. If you downloaded quake2 unzip it and play it. While you are doing that take a look at some of the graphics they look fuzzy (Unless you have a 3d card). If the graphics werent fuzzy they would look hopeless. Because of the time that it would take to "smooth" the graphic. So if you have some kind of graphic that dosent look quite right try stuffing around with the colors for a bit if done properly it will look ok if not good. This is the end of what is going to be the last tutorial in this series because I dont have enough time to write them. But eventually I might be able to write another tutorial series on sound or even 3d calculations (pick up where the other guys one left off) - Hacker (Hacker@alphalink.com.au) *** INTERMEDIATE PROGRAMMING TIPS (PART 1), by Alex Warren · alexwarren@writeme.com I hope this will become a fairly regular feature of the fanzine, designed to help those programmers who have only been programming in BASIC for a little while to improve their programs. The trouble with the term "intermediate" is that it is rather vague - in this series I'll classify an "intermediate" programmer as one who can make a program and knows the really basic things such as file I/O, simple graphics, etc., and would like to make their programs better (faster, more user-friendly, easier-to-read, or whatever else a "better" program is) I'm not sure how many parts this series will have, nor what it exactly it will cover - if anyone has any ideas or would like to donate a tip or two, please feel free to send some in. Anyway, are you sitting comfortably? Then I'll begin. TIP 1: VARIABLES AND USER-DEFINED VARIABLE TYPES This is two tips in one really... We all know what a variable is (I hope) and we all know that they come in several delicious flavours - strings, integers, long integers, and floating-point variables, for example, which each have their own uses. As a programmer, you should know the best circumstances in which to use each variable type as there are differences between them in terms of speed and in what they can store. Obviously, a string is pretty much self-explanatory, and you would never (I hope) use it to store a number (other than a phone number etc. which would need formatting). It is up to you to decide when to use the other types of variable. By default, BASIC will choose a floating-point variable if you don't specify which type the variable is going to be, and this will really slow your program down if it is doing a lot of calculations that don't require that kind of precision. If your variable is never going to store anything with a decimal point, declare it to be an integer and it will work more quickly. If you're lazy, the easiest way to make BASIC use integers by default instead of floating-point variables is to stick DEFINT A-Z at the beginning of your program. Better though, would be to explicitly state the variable type, and you can do this in two ways: integ% = 3 would set an integer variable called "integ%" to 3, as you should know. Or, you could use: DIM integ AS INTEGER integ = 3 This would set an integer variable "integ", without a percent sign, to 3. Which method you choose is up to you - if you have a large program it may be better to use the second method as then you will be able to change the variable's type by changing one word, without having to go all through the program changing the % signs to # signs, or whatever. Integers are the fastest variable types but they have disavantages. Apart from the obvious fact that they can't contain anything with decimal places, they also cannot store numbers greater than 32767 or less than -32768. (if you try to set integ% to 40000 you get an "Overflow" error). If you need bigger integer numbers, use a long integer. This can hold values from -2,147,483,648 to +2,147,483,647 and takes up twice as many bytes of memory as a short integer, and therefore will be a bit slower. The various variable types, their limits and their memory requirements should be discussed in more detail in the help file or manual for your particular flavour of BASIC. Visual Basic for Windows adds a few more flavours such as a Boolean one, which can be either True or False, and a Variant, which can be just about anything. If you have a BASIC compiler that is more modern than QuickBasic, you should have a few more too, such as a currency type for example - have a look through the types which are available, and see which types will suit your data best. "User-defined" variable types are very useful. These are basically blocks of other variables all stuck together. The following code shows an example of their use: TYPE persontype thename AS STRING * 50 phonenumber AS STRING * 20 numberofhouses AS INTEGER salary AS LONG height AS SINGLE END TYPE DIM people(5) AS persontype people(1).thename = "Bill Gates" people(1).phonenumber = "1234-567-890" people(1).numberofhouses = 353 people(1).salary = 500000000 people(1).height = 1.96 (All figures made up, in case you hadn't guessed... though maybe they aren't all that far from the truth ) As can be seen, a variable called "people" of type "persontype" is created, with five elements. This only needs to be done once - so you don't need to DIM arrays for thename, phonenumber, numberofhouses, etc., and it can be clearly seen from the code that the phonenumber and salary are related to the same thing (in this case, our old mate Bill). This is more readable than setting phonenumber(1)="1234-567-890" and height(1)=1.96, etc., for example. It also has the advantage that we can quickly, easily and efficiently copy all the data to another person or record. If you add the line people(2) = people(1) and then read the value of people(2).salary, you will see that all five pieces of data have been copied with this single statment. This is ever so much easier than having five statements such as numhouses(2)=numhouses(1) which would have been necessary had we not used user-defined types. So, as you can see, user-defined types can make life a lot, lot easier, especially if you are dealing with large amounts of data. They're also useful because you can pass them to functions - much easier than passing each element to a function. In VB5 you can also declare functions to return user-defined data types, though I don't think this is possible in QB. Anyway, as you can see, user-defined TYPEs are a powerful tool which will make your code cleaner, easier to code and easier to understand. Use them! TIP 2: SCREEN PAGE SWAPPING Ever tried making some graphics animation in your BASIC code only to find that it flickered so much it gave you a migraine? No? Then you were one of the lucky ones... Seriously though, flickering doesn't look nice and it happens when you clear the screen, draw a graphic, clear it again, draw it again, etc. - all that clearing becomes really obvious and looks terrible. However, there is a way round it, which is screen page swapping, as this program will show you. ' Screen swapping demo, by Alex Warren ' from the Basix Fanzine, Issue 12 RANDOMIZE TIMER DEFINT A-Z SCREEN 0: CLS : WIDTH 80 PRINT "Press any key to start the screen swapping demo..." DO: LOOP WHILE INKEY$ = "" SCREEN 7 PRINT "Pages are being drawn while this page is" PRINT "being displayed..." FOR i = 1 TO 7 SCREEN 7, , i, 0 FOR j = 0 TO 200 STEP i LINE (0, j)-(320, j), i NEXT j FOR j = 0 TO 320 STEP i LINE (j, 0)-(j, 200), i NEXT j FOR j = 1 TO i * 1000 PSET (RND * 320, RND * 200), RND * 15 NEXT j LOCATE 2, 2 COLOR i + 1 PRINT "SCREEN PAGE"; i NEXT i BEEP SCREEN 7, , 0, 0 LOCATE 4, 1 PRINT "Press the space bar to go to the next" PRINT "page, and press [ESC] when done" cpage = 1 DO FOR cpage = 1 TO 7 DO a$ = INKEY$ LOOP WHILE a$ <> CHR$(27) AND a$ <> " " IF a$ = CHR$(27) THEN END SCREEN 7, , , cpage NEXT cpage LOOP What this code does is draw seven pages of spectacular graphics action (well, lines and dots) into seven pages of video memory, completely hidden from view. It then instantly switches between them - no flicker, no waiting for the screen to draw - the page just pops into view. If you examine the code you'll see the secret behind this trickery is some extra numbers given to the SCREEN statement. The first number is the mode number which you usually use with the screen statement. The third and fourth numbers control the "apage" and the "vpage" respectively. The "apage" is the one that LINE statements, PRINT statements and in fact any statements that draw to the screen will be sent to. The "vpage" is the one the user will see while all this is going on. (The second number in the SCREEN statement can be safely ignored - just stick a space there instead). So, if you draw all the stuff to the apages and then flick through the vpages, the pages that were drawn pop up instantly. This technique is very useful for animation. The easiest way to use it for animation is to use something like: cpage% = 0 DO SCREEN 7, , cpage%, 1 - cpage% ' insert code here to draw screen cpage% = 1 - cpage% LOOP This will alternate between the pages; whenever page 0 is displayed, page 1 is being drawn to, and then vice versa. The 1-cpage% bits are a useful shortcut - because 1-0=1 and 1-1=0 - so they return whatever cpage% "isn't", without the need for writing IF statements such as IF cpage% = 1 THEN cpage% = 0, etc. Look in the help file for more information on screen pages. Screen 7, as used in the demonstration program, can use up to 7 on a VGA or better monitor. Screen 13, unfortunately, only has room for one, so page swapping is not possible directly from QB code, even though a modern SVGA monitor has several times the 256K memory that one screen 13 page will use. There are probably interrupts that will let you do it... perhaps this could be the subject of a future article. That's all for part 1 of my "Intermediate Programming Tips" series - if anybody can think of anything they'd like me to cover in future parts, please let me know - address at the top of the page. *** INCLUDING FILES IN EXEs, by Ollie Cook · oliver.cook@bigfoot.com This is the first programming article that I've ever written so I hope that I make myself clear enough to be understood. This article is going to take the form of a tutorial which will allow you to get this technique working, and will give you scope to adapt and update the source included. We're going to make a program which will play a WAV file, using only one executable. Let's get started. Get the code below loaded up. It includes a lot of code written by Mike Huff, and is simply to play the WAV were going to include, at a decent quality. ' +---------------------------------+ ' Ý This program is to accompany an Ý ' Ý article written by Ollie Cook Ý ' Ý about including files in EXEs. Ý ' Ý It makes use of DMA Play by Ý ' Ý Mike Huff (1996). Ý ' Ý oliver.cook@bigfoot.com - Ollie Ý ' +---------------------------------+ DECLARE FUNCTION SpeakerStatus% () DECLARE FUNCTION DMAStatus% () DECLARE FUNCTION DMADone% () DECLARE FUNCTION ResetDSP% () DECLARE SUB FMVolume (Right%, Left%, Getvol%) DECLARE SUB VocVolume (Right%, Left%, Getvol%) DECLARE SUB MasterVolume (Right%, Left%, Getvol%) DECLARE SUB MicVolume (Gain%, Getvol%) DECLARE SUB LineVolume (Right%, Left%, Getvol%) DECLARE SUB CDVolume (Right%, Left%, Getvol%) DECLARE SUB InputSource (InputSrc%, GetSrc%) DECLARE SUB WriteDSP (byte%) DECLARE SUB SetStereo (OnOff%) DECLARE FUNCTION ReadDSP% () DECLARE SUB WriteDAC (byte%) DECLARE SUB SpeakerState (OnOff%) DECLARE SUB DMAState (StopGo%) DECLARE FUNCTION ReadDAC% () DECLARE SUB DMAPlay (Segment&, offset&, Length&, Freq&) DECLARE SUB DMARecord (Segment&, offset&, Length&, Freq&) DECLARE SUB GetBLASTER (DMA%, BasePort%, IRQ%) DECLARE FUNCTION DSPVersion! () COMMON SHARED BasePort%, LenPort%, Channel%, alarmtime$ GetBLASTER Channel%, BasePort%, IRQ% 'Parses BLASTER environment SpeakerState 1 'turn the speaker on MasterVolume Right%, Left%, -1 'this puts the mixer volumes in Right% and Left% MasterVolume 8, 8, 0 '15,15,0 cranks the master volume all the way up. DIM WavBuffer(1 TO 1) AS STRING * 32767 'Make a 32k buffer for file. DIM RIFFsearch(1 TO 1) AS STRING * 4 'Make a search buffer Filename$ = "exetute.exe" Freq& = 8000 offset& = 1 OPEN Filename$ FOR BINARY AS #1 DO GET #1, 44 + offset& + (32767 * CurrentPlay!), WavBuffer(1)'Get 32k from file (skip header on WAV) CurrentPlay! = CurrentPlay! + 1 Length& = LOF(1) - 44 - offset& IF Length& > 32767 THEN Length& = 32767 'Adjust length if needed to 32k DMAPlay VARSEG(WavBuffer(1)), VARPTR(WavBuffer(1)), Length&, Freq& DO UNTIL a = 11500: a = a + 1: LOOP: a = 0 LOOP UNTIL EOF(1) CLOSE CLS PRINT "Playing Sound and Waiting 5 Seconds for It to Finish" SLEEP 5 PRINT "The END" SUB CDVolume (Right%, Left%, Getvol%) OUT BasePort% + 4, &H28 IF Getvol% THEN Left% = INP(BasePort% + 5) \ 16 Right% = INP(BasePort% + 5) AND &HF EXIT SUB ELSE OUT BasePort% + 5, (Right% + Left% * 16) AND &HFF END IF END SUB FUNCTION DMADone% Count% = INP(LenPort%) Count2% = INP(LenPort%) Count& = CLNG(Count% + 1) * CLNG(Count2% + 1) IF (Count& - 1) >= &HFFFF& THEN junk% = INP(DSPDataAvail%): DMADone% = -1 END FUNCTION SUB DMAPlay (Segment&, offset&, Length&, Freq&) ' Transfers and plays the contents of the buffer. Length& = Length& - 1 Page% = 0 MemLoc& = Segment& * 16 + offset& SELECT CASE Channel% CASE 0 PgPort% = &H87 AddPort% = &H0 LenPort% = &H1 ModeReg% = &H48 CASE 1 PgPort% = &H83 AddPort% = &H2 LenPort% = &H3 ModeReg% = &H49 CASE 2 PgPort% = &H81 AddPort% = &H4 LenPort% = &H5 ModeReg% = &H4A CASE 3 PgPort% = &H82 AddPort% = &H6 LenPort% = &H7 ModeReg% = &H4B CASE ELSE PRINT "DMA channels 0-3 only are supported." EXIT SUB END SELECT OUT &HA, &H4 + Channel% OUT &HC, &H0 OUT &HB, ModeReg% OUT AddPort%, MemLoc& AND &HFF OUT AddPort%, (MemLoc& AND &HFFFF&) \ &H100 IF (MemLoc& AND 65536) THEN Page% = Page% + 1 IF (MemLoc& AND 131072) THEN Page% = Page% + 2 IF (MemLoc& AND 262144) THEN Page% = Page% + 4 IF (MemLoc& AND 524288) THEN Page% = Page% + 8 OUT PgPort%, Page% OUT LenPort%, Length& AND &HFF OUT LenPort%, (Length& AND &HFFFF&) \ &H100 OUT &HA, Channel% IF Freq& < 23000 THEN TimeConst% = 256 - 1000000 \ Freq& WriteDSP &H40 WriteDSP TimeConst% WriteDSP &H14 WriteDSP (Length& AND &HFF) WriteDSP ((Length& AND &HFFFF&) \ &H100) ELSE IF DSPVersion! >= 3 THEN TimeConst% = ((65536 - 256000000 \ Freq&) AND &HFFFF&) \ &H100 WriteDSP &H40 WriteDSP TimeConst% WriteDSP (Length& AND &HFF) WriteDSP ((Length& AND &HFFFF&) \ &H100) WriteDSP &H91 ELSE PRINT "You need a Sound Blaster with a DSP v3.x+ to play at high speed." EXIT SUB END IF END IF END SUB SUB DMARecord (Segment&, offset&, Length&, Freq&) Length& = Length& - 1 MemLoc& = Segment& * 16 + offset& Page% = 0 SELECT CASE Channel% CASE 0 PgPort% = &H87 AddPort% = &H0 LenPort% = &H1 ModeReg% = &H44 CASE 1 PgPort% = &H83 AddPort% = &H2 LenPort% = &H3 ModeReg% = &H45 CASE 2 PgPort% = &H81 AddPort% = &H4 LenPort% = &H5 ModeReg% = &H46 CASE 3 PgPort% = &H82 AddPort% = &H6 LenPort% = &H7 ModeReg% = &H47 CASE ELSE EXIT SUB END SELECT OUT &HA, &H4 + Channel% OUT &HC, &H0 OUT &HB, ModeReg% OUT AddPort%, MemLoc& AND &HFF OUT AddPort%, (MemLoc& AND &HFFFF&) \ &H100 IF (LongByte& AND 65536) THEN Page% = Page% + 1 IF (LongByte& AND 131072) THEN Page% = Page% + 2 IF (LongByte& AND 262144) THEN Page% = Page% + 4 IF (LongByte& AND 524288) THEN Page% = Page% + 8 OUT PgPort%, Page% OUT LenPort%, Length& AND &HFF OUT LenPort%, (Length& AND &HFFFF&) \ &H100 OUT &HA, Channel% IF Freq& <= 23000 THEN TimeConst% = 256 - 1000000 \ Freq& WriteDSP &H40 WriteDSP TimeConst% WriteDSP &H24 WriteDSP (Length& AND &HFF) WriteDSP ((Length& AND &HFFFF&) \ &H100) ELSE IF DSPVersion! >= 3 THEN TimeConst% = ((65536 - 256000000 / Freq&) AND &HFFFF&) \ &H100 WriteDSP &H40 WriteDSP TimeConst% WriteDSP (Length& AND &HFF) WriteDSP ((Length& AND &HFFFF&) \ &H100) WriteDSP &H99 ELSE PRINT "You need a Sound Blaster with a DSP 3.x+ to record at high speed." EXIT SUB END IF END IF END SUB SUB DMAState (StopGo%) ' Stops or continues DMA play. IF StopGo% THEN WriteDSP &HD4 ELSE WriteDSP &HD0 END SUB FUNCTION DSPVersion! ' Gets the DSP version. WriteDSP &HE1 Temp% = ReadDSP% Temp2% = ReadDSP% DSPVersion! = VAL(STR$(Temp%) + "." + STR$(Temp2%)) END FUNCTION SUB FMVolume (Right%, Left%, Getvol%) OUT BasePort% + 4, &H26 IF Getvol% THEN Left% = INP(BasePort% + 5) \ 16 Right% = INP(BasePort% + 5) AND &HF EXIT SUB ELSE OUT BasePort% + 5, (Right% + Left% * 16) AND &HFF END IF END SUB SUB GetBLASTER (DMA%, BasePort%, IRQ%) ' This subroutine parses the BLASTER environment string and returns settings. IF LEN(ENVIRON$("BLASTER")) = 0 THEN PRINT "BLASTER environment variable not set.": EXIT SUB FOR Length% = 1 TO LEN(ENVIRON$("BLASTER")) SELECT CASE MID$(ENVIRON$("BLASTER"), Length%, 1) CASE "A" BasePort% = VAL("&H" + MID$(ENVIRON$("BLASTER"), Length% + 1, 3)) CASE "I" IRQ% = VAL(MID$(ENVIRON$("BLASTER"), Length% + 1, 1)) CASE "D" DMA% = VAL(MID$(ENVIRON$("BLASTER"), Length% + 1, 1)) END SELECT NEXT END SUB SUB InputSource (InputSrc%, GetSrc%) OUT BasePort% + 4, &HC IF GetSrc% THEN InputSrc% = INP(BasePort% + 5) AND 2 + INP(BasePort% + 5) AND 4 ELSE OUT BasePort% + 5, InputSrc% AND 7 END IF END SUB SUB LineVolume (Right%, Left%, Getvol%) OUT BasePort% + 4, &H2E IF Getvol% THEN Left% = INP(BasePort% + 5) \ 16 Right% = INP(BasePort% + 5) AND &HF EXIT SUB ELSE OUT BasePort% + 5, (Right% + Left% * 16) AND &HFF END IF END SUB SUB MasterVolume (Right%, Left%, Getvol%) OUT BasePort% + 4, &H22 'PRINT BasePort% IF Getvol% THEN Left% = INP(BasePort% + 5) \ 16 Right% = INP(BasePort% + 5) AND &HF EXIT SUB ELSE OUT BasePort% + 5, (Right% + Left% * 16) AND &HFF END IF END SUB SUB MicVolume (Volume%, Getvol%) OUT BasePort% + 4, &HA IF Getvol% THEN Volume% = INP(BasePort% + 5) AND &HF EXIT SUB ELSE OUT BasePort% + 5, Volume% AND &HF END IF END SUB FUNCTION ReadDAC% ' Reads a byte from the DAC. WriteDSP &H20 ReadDAC% = ReadDSP% END FUNCTION FUNCTION ReadDSP% ' Reads a byte from the DSP DO LOOP UNTIL INP(BasePort% + 14) AND &H80 ReadDSP% = INP(BasePort% + 10) END FUNCTION FUNCTION ResetDSP% ' Resets the DSP OUT BasePort% + 6, 1 FOR Count% = 1 TO 4 junk% = INP(BasePort% + 6) NEXT OUT BasePort% + 6, 0 IF INP(BasePort% + 14) AND &H80 = &H80 AND INP(BasePort% + 10) = &HAA THEN ResetDSP% = -1 ELSE ResetDSP% = 0 END IF END FUNCTION SUB SetStereo (OnOff%) OUT BasePort% + 4, &HE IF OnOff% THEN OUT BasePort% + 5, 2 ELSE OUT BasePort% + 5, 0 END SUB SUB SpeakerState (OnOff%) ' Turns speaker on or off. IF OnOff% THEN WriteDSP &HD1 ELSE WriteDSP &HD3 END SUB FUNCTION SpeakerStatus% OUT BasePort% + 4, &HD8 IF INP(BasePort% + 5) = &HFF THEN SpeakerStatus% = -1 ELSE SpeakerStatus% = 0 END FUNCTION SUB VocVolume (Right%, Left%, Getvol%) OUT BasePort% + 4, &H4 IF Getvol% THEN Left% = INP(BasePort% + 5) \ 16 Right% = INP(BasePort% + 5) AND &HF EXIT SUB ELSE OUT BasePort% + 5, (Right% + Left% * 16) AND &HFF END IF END SUB SUB WriteDAC (byte%) ' Writes a byte to the DAC. WriteDSP &H10 WriteDSP byte% END SUB SUB WriteDSP (byte%) ' Writes a byte to the DSP DO LOOP WHILE INP(BasePort% + 12) AND &H80 OUT BasePort% + 12, byte% END SUB Now. If we're going to append the WAV onto the end of the EXE, once compiled, we are going to have to know where the EXE ends and the WAV begins. Luckily for us, all WAV files begin with the same string: "RIFF". So, what we need to do is to make the EXE scan itself until it finds that string. So to do that, replace offset& = 1 with this: stringmatch$ = CHR$(82) + CHR$(73) + CHR$(70) + CHR$(70) OPEN Filename$ FOR BINARY AS #1 FOR loop1& = 1 TO LOF(1) - 4 GET #1, loop1&, RIFFsearch(1) IF RIFFsearch(1) = stringmatch$ THEN offset& = loop1&: EXIT FOR NEXT CLOSE #1 IF offset& = 0 THEN CLS : PRINT "No WAV file detected": STOP That will scan the file into a buffer, four bytes at a time, and check if what's in the buffer matches the header we want. We use stringmatch$ = CHR$(82) + CHR$(73) + CHR$(70) + CHR$(70) instead of stringmatch$ = "RIFF" because if we did that the routine would pick up the wrong 'RIFF' in the file. Now that the program knows where to find the WAV it's our job just to compile the program and add the WAV onto the end. (To make the sound play correctly replace 11000 in Freq& = 11000 with the actual frequency of the sound you want to attach, in Hertz). OK, now compile the code to 'exetute.exe', as that's what we referenced to in the source. Now from a DOS prompt type the following: copy /b exetute.exe + wavfile.wav That will add on the WAV file to the EXE. The EXE knows where the WAV starts and when run will play it, thanks to Mike Huff, and a little devious thinking. Please pass on any comments you may have on this article to me at oliver.cook@bigfoot.com - It's my first article, I hope you liked it. *** FONTS: AN ALTERNATIVE GRAPHIC NB: This article was originally in HTML and contained a lot of formatting, and a list of useful font characters which would have been impossible to reproduce in this text version. As a result, some of this article has been omitted. Author's Forward This article is not about programming , as such. However, it does suggest a method for improving webpages or other HTML-ized documents related to programming. IMHO, webpages and documentation both suffer a great deal from clumsy, inadequate type. This article is my own humble(?) attempt to improve upon this desperate situation. Symbology 101 One thing is certain, if something is screwed up beyond all reason then human beings have had a hand in it. So it is with the internet. I find it amazing that with all of the man-hours which the internet commands, no organization has (inadvertently) contributed more to standardizing how text is displayed to the average web-head than -- I really hate to admit this -- Microsoft. If that thought doesn't make you ralf, nothing will. IMHO, the most important aspect of internet communication is text. To produce text you need type. If two people are to communicate successfully over the internet, then they need type which is well-suited to the task. This is not how things have worked out. Webpages, for example, present a particularly bleak landscape. Fonts are very much OS specific. Needless to say, OS manufacturers are not overly concerned with inter-system compatibility regardless of how much it might benefit the user. Further confusion ensues due to the fact that almost anyone can learn to author fonts for public distribution. People just love their chaos, don't they? That said, I'd like to suggest the following to prospective webpage authors: Use the ... tag-pair for special characters found in fonts common to the Windows operating system. It's relatively simple and requires a lot less effort or storage than graphic elements. To anyone not running Windows all I can say is, "What in the blue blazes do you expect me to do about it?" According to Microsoft, the font styles common to Win 3.x and Win 95 are: Arial Courier New Times New Roman Wingdings Symbol The Symbol font offers a variety of math and logic related characters for the programmer who lusts after a great looking website. The translation tables at the end of this paper provide all of the information you will need to use characters from the Symbol font in your webpages or other HTML-ized documents. Obviously, anyone reading those pages will need to have symbol.ttf installed on their system. Some characters may be represented by either a numeric or character entity, while others have only a numeric entity as an identifier. Using entities to represent characters is very simple. All you need to specify is the name of the font, and an identifier for each of the characters that you want to reproduce. For example, joining the following lines B Í A Û (" bÎB)(bÎA) will produce [the same as -ed] B Í A Û ("bÎB)(bÎA) And that's all there is to it. Now get out there and kick some serious butt! [Symbol tables removed -ed] C'ya, RudeJohn "I'm rude. It's a job." *** TEN ODD MOMENTS Disclaimer The opinions expressed by RudeJohn do not necessarily reflect those of the Basix Fanzine or its staff. In fact, they probably disagree with me entirely. Everyone else does. Introduction Below is a short list of exercises suitable for passing the odd moment or two when you're bored silly and can't think of anything better to do. Then again, if you're that bored maybe you should be looking for a job so that you can afford to move out of your parent's basement. Think about it. One An automorphic number is a natural number which appears at the end of its square, e.g., 5² = 25 25² = 625 625² = 390625 Write a program to find more automorphic numbers. Two The Goldbach conjecture states that every even number can be represented as the sum of two prime numbers. Show that this is true for the first 1000 even numbers. Three A Mersenne prime is a prime number of the form 2^x - 1 [2 to the power of x - 1 -ed] where x is also prime, e.g., 2³ - 1 = 7. Write a program to find several more Mersenne primes. Four A perfect number is a natural number equal to the sum of all of its exact divisors except itself, e.g., 28 = 1 + 2 + 4 + 7 + 14 Write a program to find at least 3 more perfect numbers. Five Extend the notion of automorphism to higher integral powers, e.g., 5³ = 125 25³ = 15625 625³ = 244140625 Write an efficient program to search for n-th power automorphic numbers. Six Let A and B be two unequal natural numbers. If A is the sum of all of the exact divisors of B (excluding B itself), and if B is the sum of all of the exact divisors of A (excluding A itself), then A and B are amicable. For example, the sum of the exact divisors of 220 (excluding 220 itself) is equal to 284, and the sum of the exact divisors of 284 (excluding 284 itself) is equal to 220. Thus, 220 and 284 are amicable. Isn't that nice? Write a program to find more amicable numbers. Or else. Seven This exercise doesn't require a program, but you may want to write one anyway. In fact, you may want to write several! Let's say that we are looking for a simple test for a random integer generator. When do you think it would be reasonable to claim that each digit should occur 10% of the time? Less than 10%? More than 10%? If we are generating random integers in the range of say, 0 to 999, then shouldn't every number be considered as a string of digits of equal length? In other words, shouldn't the number 2 be interpreted as 002? This approach will certainly effect the frequency count for the digit zero. What do you think? Eight Write a program that will accept a simple arithmetical expression as a string and check it for unmatched parentheses. And send me a case of scotch. Nine Write a program to determine whether a simple algebraic expression is syntactically correct. This means that an expression such as X = 5 + Y / ( 3 - 3 ) is acceptable because it is syntactically correct even though it is mathematically invalid. Assume that variable names consist of a single letter, and allow + and - to be used as unary operators, e.g., X * - Y is syntactically correct but X - * Y is not. For now, restrict operations to +, -, *, and /. Ten Write a program that reads a simple arithmetical statement, checks it for syntactical correctness, and then evaluates that statement using the following rules of precedence: both unary operators share equal precedence both unary operators precede * * precedes / / precedes binary + binary + precedes binary - The overall evaluation of an expression procedes from left to right. Parts of an expression which are delimited by parentheses are evaluated before parts of the expression which are not. If parentheses are nested, then evaluation procedes from the innermost pair to the outermost pair. When confronted with two or more sub-expressions of equal precedence, evaluation procedes from left to right. [[[ Do not depend upon your programming language-of-choice to automatically enforce any of these rules. The point of the exercise is for you to define the implementation of ( ), +, -, *, and /. ]]] Accordingly, -5 + - -7 * - 4 / -2 + + 11 = 20. C'ya, RudeJohn "I'm rude. It's a job." *** BACKUS-NAUR FORM Preface Recently, I spotted a post enquiring about the existence of a BNF for some flavour of BASIC. Since BASIC newsgroups seem to attract a lot of new and inexperienced programming hobbyists, it's doubtful that any more than a handful of the people who read that post understood the question. Not that you need an advanced degree or anything, it's just that BNF doesn't come up much in conversation with BASIC programmers. Which is unfortunate, because the BNF -- or Backus-Naur form -- paints a wonderfully compact and powerful picture of a language. The purpose of this monograph is to introduce the reader to the Backus-Naur form of notation through a series of easy-to-understand examples. This paper is by no means an exhaustive treatment; it is meant to be nothing more than a bare-bones introduction to the subject. Enjoy! History Around 1959, John Backus -- one of the thirteen people on the Algol 60 committee -- proposed what is today know as the Backus-Naur form of notation for describing part of the syntax of Algol 60. Peter Naur, of the University of Copenhagen, is associated with this notation because of his modifications and extensive use of BNF as editor of the Algol 60 report. The ideas behind BNF were advanced by Noam Chomsky, a linguist, in 1956. So why isn't it called CBNF? I'll bet Noam would like to hear the answer to that one. I Never Meta-Language I Didn't Like We will begin by examining how BNF may be used to describe digits and integer constants. In BNF, the fact that 1 is a digit is expressed by (R1) ::= 1 "(R1)" is just a label. The term is delineated by angular brackets to signify that it is a meta-linguistic entity, i.e., it is part of the language we are using to describe the language under discussion. Meta-linguistic terms delineated by angular brackets are typically referred to as nonterminal symbols, or nonterminals. Characters of the language under discussion, such as the digit 1, are referred to as terminals. The rule (R1) is called a production (or rewriting) rule. Its left part is a nonterminal, and its right part is a nonempty, finite sequence of terminals and nonterminals. The symbol "::=" is read "may be composed of" (or something similar) so the rule (R1) is read A digit may be composed of the sequence of symbols: 1 To allow the digits 0 and 1 we could write ::= 0 ::= 1 We can combine these two rules using the symbol |, read as "or", to obtain ::= 0 | 1 A more comprehensive set of rules might take the form (R2.1) ::= (R2.2) ::= (R2.3) ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 The rules (R2.x) form a grammar for the language of s. The sentences of the language are the sequences of terminals that can be derived from the nonterminal . If we use the symbol => to indicate the process of rewriting, the sentence 187 may be derived as follows: => (R2.2) => 7 (R2.3) => 7 (R2.2) => 87 (R2.3) => 87 (R2.1) => 187 (R2.3) Let " =>* " represent a sequence of zero or more single derivations (or rewrites) using the production rules of our grammar. The previous derivation may then be restated: =>* 187. A Grammar for Simple Arithmetic Expressions The following grammar uses addition, subtraction, multiplication, parenthesized expressions, and integer constants as operands. (R3.1) ::= + (R3.2) ::= - (R3.3) ::= × (R3.4) ::= ( ) (R3.5) ::= According to this grammar, we derive =>* 3 × ( 4 - 7 ) as follows: => × (R3.3) => × ( ) (R3.4) => × ( - ) (R3.2) => × ( - ) (R3.5) => × ( - ) (R3.5) => × ( - ) (R3.5) => × ( - ) (R2.1) => × ( - ) (R2.1) => × ( - ) (R2.1) => 3 × ( - ) (R2.3) => 3 × ( 4 - ) (R2.3) => 3 × ( 4 - 7 ) (R2.3) The syntax tree for =>* 3 × ( 4 - 7 ) has the form: / | \ × | / | \ - | | | | | | 3 | | 4 7 The problem with syntax trees is that they don't specify the order in which some production rules are applied. For instance, the syntax tree above doesn't indicate whether ::= 4 precedes ::= 7, or vice versa. Every derivation has a corresponding syntax tree, but more than one derivation can correspond to the same tree. These derivations are considered to be equivalent. For example, => + => + => + => + => + => 2 + => 2 + 3 and => + => + => + => + => + => + 3 => 2 + 3 both correspond to the same syntax tree and are therefore considered to be equivalent. Garden of Ambiguitiy Consider =>* × - . This sentence satisfies both of the syntax trees / | \ × / | \ - and / | \ - / | \ × Any grammar that allows more than one syntax tree for some sentence is called ambiguous. The term is apt because if a sentence has two different syntax trees then it can be parsed in two different ways. This can result in a particular interpretation being assigned arbitrarily, or worse, inadvertently. Obviously, whether 2 × 4 - 3 = 5 or 2 depends upon how we parse the sentence. Dead Presidents Fortunately, it isn't difficult to specify an unambiguous grammar for simple arithmetic expressions. The solution does, however, require us to introduce a few new nonterminals. ::= | + | - ::= | × ::= | ( ) ::= ::= ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 From this grammar, it's clear that multiplication takes precedence over addition and subtraction. Thus, if you draw the syntax tree for =>* 2 + 3 × 4 you'll find that the result is 14, not 20. We can, of course, use parentheses to supercede precedence. Extensions As usual, people just can't leave well enough alone. In an effort to improve on BNF, some smart-ass suggested using braces to indicate repetition, i.e., {xyz} denotes zero or more occurrences of the sequence of symbols xyz. Using this extension, we can rewrite our grammar for simple arithmetic expressions as ::= { + | - } ::= { × } ::= | ( ) ::= { } ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 The Last Word I admire Harlan Ellison's work, but I'll never understand why he insists on being such a monumental dickweed. C'ya, RudeJohn "I'm rude. It's a job." ******************************************************************************** WANT TO SEE... YOUR AD HERE AND ON THE BASIX FANZINE WEBSITE? If so, please email basix@dewarr.globalnet.co.uk for details. Advertising can be placed here in exchange for anything that would help the fanzine - for example, webspace, a domain name, or the money to provide this - in fact, if somebody could "sponsor" the fanzine and give us www.basixfanzine.com with 10mb or more of webspace, that would be absolutely fantastic! In return, your advertisements would be sprinkled liberally here and there in the fanzine and on the website too. ******************************************************************************** YOUR PROGRAMS useful programs demonstrating useful techniques *** DETECTING THE PARALLEL PORT, from Juan F. Miguez · jfm7620@megahertz.njit.edu / miguez@andromeda.rutgers.edu / miguez@bifoot.com (take your pick... I'm sure that last one should be miguez@bigfoot.com really, but that's what it said in the code I recieved -ed) This program demonstrates how to detect the parallel port automatically: '############################################### '### Juan F. Miguez 7-1-98 ### '### Detects the Parallel Port Automatically ### '### The condition here is that if the info ### '### gathered from the port is 255, then the ### '### parallel port does not exist. ### '### Send all the comments to: ### '### miguez@bifoot.com ### '############################################### 'Basix Fanzine editor's note - perhaps the email address is really ' miguez@bigfoot.com ?? ' #### Define the parallel ports as par1 and par2 par1 = &H378 par2 = &H3BC ' #### If the input from the port is 255 then the port does not exist ' #### INP sends acknowledges a bit from the specified port ' #### as INP(par1) gets a bit from the 378 parallel port and tests it. IF (INP(par1) <> 255 AND INP(par2) <> 255) THEN LOCATE 12, 12 PRINT "Both Parallel ports &H378 and &H3BC were found. " INPUT "Which one would you like to use for the experiment?"; ParPort$ IF (ParPort$="&H378") then P=&H378 IF (ParPort$="&H3BC") then P=&H3BC ELSE IF (INP(par1) < 255) THEN ParPort$ = "&H378" ' Parallel port is 3BC" P = &H378 ELSEIF (INP(par2) < 255) THEN ParPort$ = "&H3BC" ' Parallel port is 378 P = &H3BC END IF END IF PRINT "Your parallel port is located at: "; ParPort$ END *** BINARY FILE ENCRYPTION, from Daniel Bolger · daniel.bolger@ukonline.co.uk Daniel Bolger writes: "It works by adding the ascii numbers from each letter of the password together and then dividing by the number of letters -- basically finding the average. Then things get XORed etc. It originated as a copier - and a fast one at that, but now it isn't very fast - perhaps you could change that. Anyway, I hope it is of use." 'File encrypter Copyright Daniel Bolger 1998 DECLARE FUNCTION Encrypt$ (strenc AS STRING, pass AS STRING) DIM tenner AS STRING * 10 DIM oneer AS STRING * 1 DIM hundreder AS STRING * 100 DIM thousander AS STRING * 1000 CLS INPUT "Which file do you want to do today"; InFile$ INPUT "As what"; OutFile$ INPUT "Password"; pass$ OPEN InFile$ FOR BINARY AS #1 OPEN OutFile$ FOR BINARY AS #2 TotalSize = LOF(1) RemainingSize = TotalSize counter = 1 DO UNTIL RemainingSize = 0 buffer$ = "" SELECT CASE RemainingSize CASE IS >= 1000 choice$ = "thousander" RemainingSize = RemainingSize - 1000 CASE IS >= 100 choice$ = "hundreder" RemainingSize = RemainingSize - 100 CASE IS >= 10 choice$ = "tenner" RemainingSize = RemainingSize - 10 CASE ELSE choice$ = "oneer" RemainingSize = RemainingSize - 1 END SELECT IF choice$ = "oneer" THEN GET #1, , oneer oneer = Encrypt(oneer, pass$) PUT #2, , oneer ELSEIF choice$ = "tenner" THEN GET #1, , tenner tenner = Encrypt(tenner, pass$) PUT #2, , tenner ELSEIF choice$ = "hundreder" THEN GET #1, , hundreder hundreder = Encrypt(hundreder, pass$) PUT #2, , hundreder ELSEIF choice$ = "thousander" THEN GET #1, , thousander thousander = Encrypt(thousander, pass$) PUT #2, , thousander END IF LOOP PRINT PRINT "Finished (wasn't that quick?)" CLOSE SYSTEM FUNCTION Encrypt$ (strenc AS STRING, pass AS STRING) FOR i = 1 TO LEN(pass) cstring$ = MID$(pass, i, 1) casc = ASC(cstring$) tasc = tasc + casc NEXT i tasc = tasc / LEN(pass) FOR i = 1 TO LEN(strenc) cstring$ = MID$(strenc, i, 1) casc = ASC(cstring$) casc = casc XOR tasc cstring$ = CHR$(casc) MID$(strenc, i, 1) = cstring$ NEXT i Encrypt$ = strenc END FUNCTION *** CONTROL+BREAK DISABLER, from Daniel Bolger · daniel.bolger@ukonline.co.uk Daniel Bolger writes: "This is a version of NoBreak (I call DazNoBreak). It disables the use of the Cntrl + Break and the Cntrl + C keyboard shortcuts for exiting programs in QBasic. I believe [the Basix Fanzine] had a program like this in the past... I hope this is clearer. It isn't based on the previous version and any similarity is purely coincedental. Some disadvantages: 1. You cant use Num Lock or Caps, they stop it working, so they are turned off at program startup. They are prevented from going back on. At program end, they resume their status before the program was run. 2. Every time you use the two aforementioned shortcuts, the scroll lock toggles! 3. More seriously: you can't use INPUT, or LINE INPUT, although you can use INKEY$, and INPUT$() as in the example. I hope you like it." DECLARE SUB CLEARLOCKS () CLS KEY 15, CHR$(0) + CHR$(29) 'Control (neccessary for DazNoBreak) KEY 16, CHR$(0) + CHR$(69) 'NumLock KEY 17, CHR$(0) + CHR$(58) 'CapsLock KEY 18, CHR$(0) + CHR$(70) 'ScrollLock ON KEY(15) GOSUB NOBREAK ON KEY(16) GOSUB HandleLocks ON KEY(17) GOSUB HandleLocks ON KEY(18) GOSUB HandleLocks KEY(15) ON KEY(16) ON KEY(17) ON KEY(18) ON DEF SEG = 0 OriginalStatus% = PEEK(&H417) 'Find original status of Lock keys CLEARLOCKS DO UNTIL I$ = chr$(27) I$ = INPUT$(1) IF ASC(I$) >= 32 THEN PRINT I$; LOOP POKE &H417, OriginalStatus% 'Restore original status of Lock keys SYSTEM NOBREAK: RETURN HandleLocks: CLEARLOCKS RETURN SUB CLEARLOCKS Status% = PEEK(&H417) 'Read keyboard status. IF Status% <> 130 THEN POKE &H417, 130 END SUB *** "A SCREENSAVER TYPE THING", from Mike Anderson · MikeAinIA@aol.com His words, not mine :) "I've sent you this instead of a good article. :-)" he says... '--------------------------------------------------------------------- '| A Screensaver type thing | '| Uses Screen 12 | '| Runs until mouse moves, or key is pressed | '| Has midnite rollover checking and should run about the | '| same speed on any CPU. | '| As a screensaver, it's pretty lame, but I actually use it! | '| I hot-key into it from Win95, with properties set to give | '| it priority. It keeps the hard-disk from thrashing while a | '| real screensaver runs, because I set the properties | '| to keep the real screen from starting! | '--------------------------------------------------------------------- 'Blankbox.BAS by Mike Anderson 'Draws a screen full of ellipses, erases them one at a time ' then draws a screen full of rectangles and erases them one ' at a time. Runs until mouse or keyboard action. DEFINT A-Z DECLARE SUB MIDNITE () DECLARE SUB Dlay (Sng!) DECLARE SUB Mouse (m1%, m2%, m3%, m4%) DECLARE SUB Mousenow (leftbutton%, rightbutton%, xmouse%, ymouse%) DECLARE FUNCTION MouseInstall% () DECLARE FUNCTION DrawBox () DECLARE FUNCTION DrawCirc () CONST TRUE = -1 CONST FALSE = NOT TRUE ' $INCLUDE: 'qb.bi' RANDOMIZE TIMER ' The following structures are used to erase the randomly ' drawn figures. TYPE Circs R AS INTEGER 'R is horiz. pos of center T AS INTEGER 'T is vert. " " " L AS INTEGER 'L is Radius A AS SINGLE 'A is aspect ratio (we're really drawing END TYPE ' ellipses) TYPE Boxes R AS INTEGER 'R is Right edge L AS INTEGER ' Left edge T AS INTEGER ' Top B AS INTEGER ' Bottom END TYPE DIM SHARED AllCircles(50) AS Circs 'Array of Ellipses drawn DIM SHARED AllBoxes(50) AS Boxes 'Array of Boxes drawn DIM SHARED ThisCirc AS Circs 'Ellipse buffer DIM SHARED ThisBox AS Boxes 'Box buffer SCREEN 12 CLS x = MouseInstall 'check for mouse IF x THEN 'If found, xmouse% = 0 ' store the position ymouse% = 0 Mousenow lbut, rbut, startx, starty END IF x = TRUE DO IF x THEN x = DrawCirc 'DrawCirc is a function - returns TRUE ELSE 'Until finished, then returns false x = DrawBox 'DrawBox function returns false until END IF 'finished, then returns true 'After each circle or box check the mouse position 'and quit if it has moved Mousenow lbut, rbut, xnow, ynow IF xnow <> startx AND ynow <> starty THEN SYSTEM 'If the mouse hasn't moved, check the keyboard 'and quit on any key. R$ = INKEY$ IF LEN(R$) THEN SYSTEM LOOP SUB Dlay (Sng!) Now! = TIMER DO TElapsed! = TIMER - Now! IF TElapsed! < 0 THEN 'Midnite hath passed! MIDNITE ' Announce it! EXIT SUB ' Possible change - announce END IF ' every hour, half-hour, or 1/4 hour LOOP WHILE TElapsed! < Sng! END SUB FUNCTION DrawBox STATIC DrawBox = FALSE Dlay (.2) L = INT(640 * RND): ThisBox.L = L R = INT(640 * RND): ThisBox.R = R T = INT(480 * RND): ThisBox.T = T B = INT(480 * RND): ThisBox.B = B C = INT(15 * RND) + 1 AllBoxes(count%) = ThisBox 'save characteristic of ThisBox 'to array of all boxes Numbox = 50 ' 50 fills the screen nicely - if ' you change it, change the DIM statement ' for AllBoxes also. IF count% >= Numbox THEN IF erased% >= Numbox THEN 'If all are drawn, and all are erased count% = 0 ' start over erased% = 0 DrawBox = TRUE ' Return TRUE, to switch to ellipses Dlay (.4) ELSE '(keep erasing) ' Watch it - the next line is a long one! LINE (AllBoxes(erased%).L, AllBoxes(erased%).T)-(AllBoxes(erased%).R, AllBoxes(erased%).B), 0, B erased% = erased% + 1 END IF ELSE '(keep drawing) LINE (L, T)-(R, B), C, B count% = count% + 1 END IF END FUNCTION FUNCTION DrawCirc STATIC DrawCirc = TRUE Dlay (.2) L = INT(240 * RND) 'set the "Radius" A! = INT(10 * RND) + 1 'Set the aspect ratio H = INT(2 * RND) + 1 ' Flip a coin IF H = 1 THEN A! = 1 / A! ' If "heads" then invert the aspect ratio 'This next bit of gymnastics keeps the entire figure on the screen IF A! < 1 THEN R = INT(RND * (640 - (2 * L))) + L T = INT(RND * (480 - (2 * A! * L))) + (A! * L) ELSE R = INT(RND * (640 - (2 * (1 / A!) * L))) + ((1 / A!) * L) T = INT(RND * (480 - (2 * L))) + L END IF C = INT(15 * RND) + 1 'Pick a color, except black ThisCirc.R = R ThisCirc.T = T ThisCirc.L = L ThisCirc.A = A! AllCircles(count%) = ThisCirc 'save the characteristics in the array Numbox = 50 '50 is a nice number - if changed, be sure to change 'the DIM statement for AllCircles array IF count% >= Numbox THEN 'Have we drawn all 50? IF erased% >= Numbox THEN 'Yes. Have we erased all 50? count% = 0 'Yes, so clean up erased% = 0 DrawCirc = FALSE 'Return FALSE, to switch to boxes Dlay (.4) ELSE 'No - Keep erasing. 'Next line is a long one - watch for wrapping CIRCLE (AllCircles(erased%).R, AllCircles(erased%).T), AllCircles(erased).L, 0, , , AllCircles(erased%).A erased% = erased% + 1 END IF ELSE 'Not done drawing - CIRCLE (R, T), L, C, , , A! 'Draw next one count% = count% + 1 END IF END FUNCTION DEFSNG A-Z SUB MIDNITE CLS 'Announce that Midnite has passed LOCATE 12, 36 COLOR 15 PRINT "MIDNITE" ' Play a tune SOUND 1300, 12 SOUND 30000, 2 SOUND 1000, 12 SOUND 30000, 2 SOUND 1150, 12 SOUND 30000, 2 SOUND 760, 12 SOUND 30000, 2 SOUND 760, 12 SOUND 30000, 2 SOUND 1150, 12 SOUND 30000, 2 SOUND 1300, 12 SOUND 30000, 2 SOUND 1000, 16 COLOR 7 CLS END SUB DEFINT A-Z SUB Mouse (m1%, m2%, m3%, m4%) 'Mouse interrupt handler DIM InRegs AS RegType, OutRegs AS RegType InRegs.ax = m1% InRegs.bx = m2% InRegs.cx = m3% InRegs.dx = m4% INTERRUPT &H33, InRegs, OutRegs m1% = OutRegs.ax m2% = OutRegs.bx m3% = OutRegs.cx m4% = OutRegs.dx END SUB FUNCTION MouseInstall% 'Checks for existance mflag% = FALSE 'Assume it's not there Mouse mflag%, 0, 0, 0 MouseInstall% = mflag% END FUNCTION SUB Mousenow (leftbutton%, rightbutton%, xmouse%, ymouse%) Mouse 3, m2%, xmouse%, ymouse% leftbutton% = ((m2% AND 1) <> 0) rightbutton% = ((m2% AND 2) <> 0) END SUB ******************************************************************************** LETTERS your questions answered, your comments printed... *** PROGRAMS, MIDI & INP, from Daniel Bolger · daniel.bolger@ukonline.co.uk Hi Below, I have included the source of my binary file encrypter... [included above] One more piece of code: This is a version of NoBreak (I call DazNoBreak). [also included above] Cheers, Daniel Bolger :-) (Age 12 - no kidding!) PS. Great fanzine, BTW is it possible to play midi files in QB? Perhaps you could go over things like INP which means nothing to me... Thanks for the programs. It is indeed possible to play MIDI files from QB, but not directly. It can be done using the QMIDI routines - the URL is in the Internet Resources section of the fanzine, and you can download it directly by clicking this link: http://members.tripod.com/~jdorland/qmidi/qmidi35.zip INP is the opposite of OUT, and you use it for reading info from the ports. I don't use it very much, probably the only time I need it is when reading/writing the palette info (though this can be done in QB already using the PALETTE command, but I find using OUT easier). Anyway, the following SUB uses OUT and sets colour number n to the colours specified in r, g, and b. (The Red, Green, and Blue values) SUB pal (n AS INTEGER, r AS INTEGER, g AS INTEGER, b AS INTEGER) OUT &H3C8, n OUT &H3C9, r OUT &H3C9, g OUT &H3C9, b END SUB If you turn OUT to INP in the last three lines, they return the r, g and b values rather than set them. So you can read the r, g and b values of colour 200 by using: OUT &H3C8, 200 R = INP &H3C9 G = INP &H3C9 B = INP &H3C9 There are many other uses of INP and OUT - they're used in programming the SoundBlaster for example. They can also control other things as well - just about any piece of hardware connected to your computer can be controlled via INP and OUT, if you know the various numbers. I have uploaded a file that I found somewhere on the web to the Basix Fanzine website, it lists many of these ports and the values they take. You can download it directly by clicking this link - http://www.users.globalnet.co.uk/~dewarr/ports.txt ******************************************************************************** WANT TO SEE... YOUR BASIC PRODUCT REVIEWED IN THE FANZINE? If so, please email basix@dewarr.globalnet.co.uk for details. If you market a compiler or other BASIC-related product and want the DOS BASIC world to know about it, why not send in a review copy? It could be emailed to the address above (please ask first though, before you plant a massive binary in my mailbox) or, if you're kind enough, you could post a copy - email me for the address. ******************************************************************************** INTERNET RESOURCES GETTING THE FANZINE Website http://come.to/basixfanzine From here, you can download all issues of the Basix Fanzine in text or HTML format, download useful utilities and documentation, read issues online, and get up-to-date news and information. Newsgroups The Basix Fanzine is posted when it is released to alt.lang.basic, alt.lang.powerbasic, comp.lang.basic.misc and microsoft.public.basic.dos, in a zip file containing the HTML files for that issue. If you want it posted to any other BASIC newsgroups then please let me know. You can download the old-fashioned text format versions of the HTML issues at the Basix Fanzine website, URL above. Mailing List To get the Fanzines as they are released, join Tony Relyea's mailing list by sending an email to the new address of fanzine@vt.edu with subject "subscribe basix-fanzine". This mailing list is completely separate from the Basix Fanzine so I cannot accept responsibility for any emails you do - or don't - get when you join the mailing list. USEFUL BASIC WEBSITES To read more information about a particular site, click the [info] link next to the URL. Compilers -PowerBASIC (also FirstBasic, PB/DLL and PB/CC): http://www.powerbasic.com -EMS (old MS compilers): http://www.wdn.com/ems/oldtools/ms.htm -Provantage (old MS compilers): http://www.provantage.com NEW URL: Old compilers: http://weber.u.washington.edu/~bpwilson NEW URL: BASM: http://www.users.uswest.net/~sdiggins/basm.html BASIC code -The Beginners Basic Homepage: http://www.users.globalnet.co.uk/~basic/ -QBasic.com: http://www.qbasic.com -The Programmer's Page: http://www.professionals.com/~peterp/ -ABC Packets (bi-monthly collections of useful BASIC code): http://come.to/abcpackets NEW MIRROR: There is a new UK mirror for the ABC Packets at http://www.cvnet.co.uk/o.cook/abc NEW URL: PowerBasic Archives: http://www.xs4all.nl/~excel/pb.html -Tim's QuickBasic Page: http://www.geocities.com/SiliconValley/Heights/8967/ -QBasic Programming Corner: http://www.geocities.com/TheTropics/9964/qbasic.html -The QBasic Site: http://hem.passagen.se/hedsen -DMAPLAYH.BAS (WAV player): http://www.ocf.berkeley.edu/~horie/project.html -The QuickBasic Enhanced Programming Page: http://www.geocities.com/SiliconValley/Lakes/7303/ -Blood 225's BASIC stuff: ftp://users.aol.com/blood225 -Alex Warren's BASIC page: http://www.users.globalnet.co.uk/~dewarr/basic.htm Libraries -Zephyr Software (SVGA Library): http://www.zephyrsoftware.com -MOD Library: http://www.fortunecity.com/millenium/celesteville/23/index.html -QMIDI (MIDI player): http://members.tripod.com/~jdorland/qmidi/ Reference NEW URL: Ralf Brown's Interrupts List: http://www.cs.cmu.edu/afs/cs/user/ralf/pub/WWW/files.html (also available at http://www.ctyme.com/rbrown.htm) NEW URL: Programmers' File Formats Collection: http://www.wotsit.org -Basix Fanzine: http://come.to/basixfanzine -X2FTP: ftp://x2ftp.oulu.fi/pub/msdos/programming/ -PCGPE (PC Games Programmers' Encyclopaedia): ftp://x2ftp.oulu.fi/pub/msdos/programming/gpe Add your site to this list by sending an email to basix@dewarr.globalnet.co.uk. Also, if any of the sites disappear or move address, please send an email so I can update this page when I release the next issue. USEFUL BASIC NEWSGROUPS alt.lang.basic alt.lang.powerbasic comp.lang.basic.misc microsoft.public.basic.dos NEW: comp.lang.basic.powerbasic GETTING HOLD OF BASIC QBasic: QBasic is free and available on DOS disks (versions 5.0 and up), the Windows 95/98 CDROMs, and within http://www.microsoft.com/windows/download/olddos.exe. QBasic supports a lot of what QuickBasic does, except that it does not compile and has no built-in support for interrupts. GW-BASIC: Versions of DOS prior to 5.0 included GW-BASIC rather than QBasic. The last version was v3.23. If you have any really old DOS disks, look on those, or you can search for it on the web. I think there is a link to it at Ollie Cook's ABC UK Mirror - address above. GW-BASIC is rather inferior to the likes of QBasic, which is compatible with it, so I wouldn't bother with GW-BASIC, personally. Unless you hate user-friendliness and have a bizarre fetish for line numbers, of course. Commercial Microsoft BASICs: You can order new and used copies of QuickBASIC, PDS 7.x, VBDOS, etc. online at http://www.wdn.com/ems/oldtools/ms.htm, http://www.provantage.com and http://weber.u.washington.edu/~bpwilson. These usually cost upwards of US$100. QuickBASIC is the "big older brother" of QBasic. PDS is the "even bigger brother" and VBDOS is a BASIC flavour that allows the easy creation of user interfaces (UIs). It is more-or-less compatible with Visual Basic for Windows - you can port VBDOS code to VB5 if you have the patience. It is worth noting that Microsoft is no longer supporting its DOS versions of BASIC. PowerBasic: You can buy PowerBasic, FirstBasic, PB/DLL and PB/CC from http://www.powerbasic.com. PowerBasic (current version 3.5) is fairly compatible with Microsoft BASICs but has no support for Screen 13, for some reason I've never bothered to find out about. Libraries are available for this though. FirstBasic is a shareware version of PowerBasic 2.1 and supports most of what QuickBasic does, though with some syntax differences. PB/DLL and PB/CC work with Windows (PB/CC will soon have versions for other operating systems). PowerBasic flavours all have the advantage of the MS flavours that they are still being supported. There are other freeware/shareware compilers available such as OmniBasic, Liberty Basic (for Windows), and more. One day I'll even give you the links :) If you want to compile very few programs which have been made using QBasic, and don't want to shell out loads of money for a compiler, you can pay $5 a time for compiling at http://members.aol.com/qbasicnow. Email qbasicnow@aol.com for more information on this. NEW: "Simcop" tells me he will compile programs for free. His email address is simcop2387@aol.com, and his homepage is at http://members.aol.com/simcop2387/index.html. QB4.5 and several other compilers can be also be downloaded illegally from various websites. The Basix Fanzine does not accept responsibility for any damage caused to your computer or your life through downloading illegal software - you have been warned. If you know of any other compilers or would like to advertise yours here, send an email to basix@dewarr.globalnet.co.uk, or post a message on one of the BASIC newsgroups and hope that I see it. ******************************************************************************** FINAL WORDS Thanks to the following for contributing articles and source code for this issue, in no particular order: "Hacker" aka Damian Nikodem RudeJohn (only one word - not "Rude John", as I wrote in the last issue, I'm informed ), aka "The Tripods" or "When The Tripods Came", and now "Sanctuary". Who knows, maybe he even has a real name. Juan F. Miguez Daniel Bolger Ollie Cook Finally, thanks to "Rembrandt Packaging" aka Jeroen and Marc van den Dikkenberg for pointing out a few old links in the "Internet Resources" section. NEXT ISSUE: Well, hopefully I'll have the next issue - the last fanzine of 1998 - out by the end of October. But, to do that, I need your contributions - so send something in! Alex Warren, 14th August 1998