QB    ON   ACID     
                               [smalogo.gif]
                                      
                            December 21st, 1999
                                      
        Welcome to issue #4 of our lil online zine. We're HUGE this
     time...over 70K of text alone! Not counting images and whatnot of
    course...anyways, prepare for some serious coding examples and a lot
            of info in this issue...so let's shut up and dig in!
     _________________________________________________________________
                                      
                           LETTERS TO THE EDITOR
                                      
   From Blair Pyle (aka Big Nose)
   
   I'd like to take a moment to respond to Zkman's letter from last
   issue. In no way are the Phat Kids inexperienced. Just because we
   haven't had any earlier projects posted until recently (Holy Conquest)
   in no way means that we are inexperienced. Fat Phil and myself have
   been making games for almost 7 years. We started by modifying Nibbles
   and as we learned more we made somewhat better stuff. We didn't have
   access to libraries off of the internet or anything like that until
   Groovin got access to the Internet. That's when we first got access to
   libraries and other stuff. I really must say that calling the Phat
   Kids inexperienced is a very ignorant comment and I should expect it
   only from an individual who can't see past his own face.
   
   Thank you.
   
   Editor's Note: This is what we're all about...allowing the readers to
   state their opinions. If you have any responses to this letter, please
   feel free to write to us.
   
  From Wafn
  
   I be inna December QBoA, wee :)
   
   Anyway, er, I actually enjoyed this latest issue of QBoA, some very
   valid rants/articles, and ones that interested me, too. That's very
   hard to find nowadays, mm?
   
   I also wanted to give QbProgger a virtual cookie for finally writing
   something that makes sense >:)
   
   One thing I would really like in this e-zine.. is something that will
   teach. Too many of the articles are just talking about theory, ranting
   about things, and so on. Although this is quite entertaining, it needs
   something solid to supplement it :)
   
   Why not write an article on how to load GIFs properly in QB, since
   you, Nek, and QbP seem to be able to do this pretty good.
   
   This is a QB magazine, if the title of it is any indication of the
   language, and a QB magazine should have something directly relaring to
   QB, no? :)
   
   Ahh... well, great job, you'd better not discontinue this thing.. this
   'EFnet diskmag' couldn't be much better ;)
   
   Editor's Note: Discontinue? Not a chance in hell at this point! But
   we'll try to find some people willing to do more teaching articles.
   
                                Back 2 Top 
     _________________________________________________________________
                                      
                                  The News
                                      
  New NES Emulator?
  
   Yes! According to the creator, a new NES emulator, written in 100%
   QuickBASIC 4.5, is in development! According to Bloodknight, the
   author of this emulator, it will support all 160 mapper types and all
   256 6502 opcodes. We got a chance to view a very early copy of the
   source code, and it is very very complex. This emulator will run in
   ModeQ, 256x256x256 colours, whether or not it will support sound is
   currently unknown. Of course, being pure QB will make it very slow,
   but this is just another example of how people are trying to break the
   rules in QB.
   
  Neozones...what are they DOING!
  
   For those who don't know, there now exists neozones.com! Yes,
   NeoZones, one of the largest online QB community centers, finally gets
   its rightful place in cyberspace. Apparently there was some
   miscommunication between Chuck of quickbasic.com and Spacehog, and
   old-school QBer, about domain issues, and in the mix, Enhanced
   Creations was lost. Well, it's back online at http://ec.neozones.com/
   for the time being.
   
                                Back 2 Top 
     _________________________________________________________________
                                      
                             State Of The Scene
                                      
   The QB 'scene' has been quite pathetic and lame of recent times. First
   of all though, let me tell you that have no wanting of re-igniting any
   of these stupid childish feuds. I am simply ruminating over the
   semi-recent events.
   
   First of all was the almost dead "using libs means you are not writing
   your own program" argument, which was re-started by another feud, more
   on that one later. Of the ceaseless banter back and forth, Darkdread
   summed it up best. Why create your own gfx lib if someone has already
   done it? Using JFont means I cannot program? I do use GSLib for its
   blazing speed. I could program my own set, but it would not be nearly
   as fast and would be time consuming, so what would be the use? Look at
   C, you can't use the language without libs.
   
   Then there is the issue of using code without credit. Credit should
   definitely be given where due. In my own lil project (not an RPG), I
   have credited 10-15 people, even people whose code I just examined and
   learned from, later re-building from scratch for my own purposes. Then
   there was the issue of ripped gfx. I personally find it fine as long
   as it is not the final gfx, permission is asked, and credit is given.
   It is just really pathetic that ppl take gfx, and then call it their
   own. And lastly was the ripped web content. My own two sites (Simply
   Qbasic and QNN) were supposedly ripping content from Neozones. This
   showed the pathetic side. Some people had thought that I had ripped my
   files section from neozones, but not a SINGLE one of them told me
   that. 15k+ hits and I never knew. Once I did find out, I changed the
   layout. My other site was also said to have stolen the design from
   Neozones (to which I say stfu, if you have seen the site, you'll know
   why) and that my news was all sugar candy and sucking up. Its just
   news! Just letting other people know of some developments! And sucking
   up to whom btw? =)
   
   Lately, quickbasic.net also created a furor over ripping interviews
   and what not. Ripping an interview from LordQB to using other's code
   to old news and other site. Qb Sites permeate lameness ;-p
   
   Talking about qb sites, Qbasic top 50 and the other lists have all
   becomes jokes. How did quickbasic.com, down at the time, cone out on
   top? How does qbsource.com, which is still 'revamping' from 3 months
   ago, come on top of all those lists without any content? All the lists
   are screwed. Future Software had Nightwolf Productions suddenly from
   out from no where with 67 votes, and then suddenly jumped another 10.
   Top Ranked Sites also has a multitude of same IPs saying one site
   rocks, while the same IPs have been seen ranking other sites 1
   multiple times with the always descriptive 'sucks.'
   
   There was also the bashing that Razor got. Ok, it was late, was
   skimpy, but instead of saying what shit it was and else, you guys
   could have told Terminator what to improve on. I have talked to
   speige, the new editor, about many improvements, and he said he would
   implement them.
   
   Looking at all this, this is an overall condescending view by the more
   'elite' QB programmers (*ducks under the flood of hate mail). A while
   ago, BattleCraft99 posted on the Neozones qboard about some programs.
   Instead of constructive criticism (yes ppl, you can do it), he was
   just told how stupid and what a newbie he was. Gimme a break. You same
   ppl were never newbies? Came out of the womb all smart and
   intelligent? ;-p Also the stupid little argument over Nexus_13. Nek
   was overly harsh on his lib ;-). And this condescension is found
   throughout the 'scene.' Truly pathetic. I myself was around in '97
   when Tsugumo came out of nowhere with TheGame, had his gfx ripped by
   Tek (I still remember that there was even a petition ;-]), and
   DarkDread got hacked and left. It was pitiful. I was called stupid and
   what not for not fully knowing the palette statement (Qbasic 1.1 help
   is awful ;-p), and left utterly disgusted. Then this spring '99, after
   learning some other languages, I decided to come back with my newfound
   'intelligence'. Seeing Qbasic Top 50, Dark Ages, DirectQB, Monospace,
   and others, I thought things had finally changed. Damn was I wrong. As
   the number of qb programmers dwindle, people still insist on being
   assholes. Being one is ez mind you.
   
   And that about concludes my rant, and what a rant it is ;-).
   
   Btw, all flames, comments, bomb threats (mind you, we have nukes!
   Heheh) and anything else can be directed to: ahmedfq@hotmail.com
   
                                  By Ahmed
                                      
                                Back 2 Top 
     _________________________________________________________________
                                      
                  QB parameter passing (technical edition)
                                      
   Hey again to all our favourite readers.
   My friend Nodtveidt asked me to do another one of my special articles.
   
   This time im going to explain a bit about QB parameter passing, yes i
   know alot of you know this already, but for the newbies out there (who
   happen to know asm by heart :) read on.
   
   Assumptions:
   QuickBASIC 4.5 (no other compiler or version)
   MASM 6.11d (or newer, tasm is no good in my humble opinion)
   
   Lets start off with common variables. Normally, they are passed by
   reference, this is the same way QB does it internally between subs and
   functions.
   
By reference Example program:

BASIC:
        DECLARE FUNCTION MyInteger& (Integ%, Lon&)

        t& = MyInteger(123, 456)
        PRINT t&

MASM:
        .model medium, basic
        .386
        .code
        MyInteger proc public uses bx cx si di ds es Integ:word, Lon:word
        
        mov bx, Integ
        mov ax, [bx]
        
        ; ax now contains the value of Integ% (123)
        
        mov bx, Lon
        mov ax, [bx]
        
        ; ax now contains the lower 16 bit of Lon
        
        mov dx, [bx+2]
        
        ; dx now contains the upper 16 bit of Lon
        
        inc ax
                
        ret
        
        MyInteger endp
        end
        
        SCREEN OUTPUT: 457

   Explanation:
   
   In the basic module, i pass the value 123 by reference. What happens
   is the value is moved to a temporary location in the common data
   segment, and i retrieve MyInteger's return value and print it.
   
   In the assembly module, i use a VERY handy way of referencing
   parameters. ".model medium, basic" tells the assembler i want a medium
   sized memory configuration which is identical to QB's (dont use any
   other, it wont do anything to make your modules smaller or faster, but
   only to make it crash). The basic parameter tells the assembler we are
   using BASIC parameter passing technique (its pretty much identical to
   PASCAL but they where nice enough to give it its own name). This way
   we dont have to count where in the asm routine's stack we keep the
   variables, they are automatically handled by masm, and BP is set up.
   Don't worry, the code is NOT slower or bigger than the hand coded
   technique, it is exactly the same.
   
   Down the line we find "uses", this tells the assembler that we use
   these registers, its only there to make the code look alot better, but
   you can use the regular way, if you like. I typed in all the registers
   QB wants you to save, of course if you dont use them all you could
   just remove those from the list.
   
   By reference means a 16bit OFFSET pointing to the actual variable. And
   you must NOT tamper with DS if you want to be able to reference them.
   It is slower to use this technique, but if speed is not an issue, it
   does make things look better for the programmer, and makes it more
   userfriendly, in my humble opinion. One advantage with by reference
   passing is your ability to alter the parameter variables. That way you
   can return more values.
   
   LONG variables are 32bit signed integers. These can be a bore to
   handle, since you need two 16bit registers. I usually use a 32bit
   register for them, makes things easier to load and store. If you use
   32bit registers, you still have to save the lower 16bit of those
   registers.
   
   ** RETURNING VALUES are simple.
   If you define MyInteger to return an Integer then AX must contain the
   returning value.
   If you define MyInteger to return a Long then DX:AX must contain the
   returning value.
   Returning values are passed by value, not by reference.
   
By value Example program:
        
        DECLARE FUNCTION MyInteger& (BYVAL Integ%, BYVAL Lon&)

        t& = MyInteger(123, 456)
        PRINT t&

MASM:
        .model medium, basic
        .386
        .code
        MyInteger proc public uses bx cx si di ds es Integ:word, Lon:dword
        
                mov ax, Integ
        
                ; ax now contains the value of Integ% (123)
        
                mov eax, Lon
        
                ; eax now contains the value of Lon& (456)
        
                inc ax
                
                ret
        
        MyInteger endp
        end
        
        SCREEN OUTPUT: 457
        

   STRINGS are a bit tricky, a single little screw up and your program
   will crash. do not try to pass these byvalue, its not a good thing. A
   16bit offset is passed instead, this points to a header that looks
   roughly like this:
   
string_length  word SIZEOF string_string
string_offset  word OFFSET string_string
<....>
string_string  byte 'my string is here'

   A simple example here:
   

in BASIC:
        declare function mystr$ (a$)
        
        a$="lala"
        b%=mystr(a$)
        print b%
        
in MASM:
        .model medium, basic
        .386
        .code
        mystr proc public uses bx cx si di ds es astr:word
                
                cld
                
                mov bx, astr
                mov cx, [bx]
                
                ; cx contains LENGTH of astr (a$)
                
                lds si, [bx+2]
                
                xor ax, ax
                lodsb
                
                ; ax contains ASCII value of first character in astr.
                
                ret
        mystr endp
        end
        
   Simple as that, there you got the string position and length, no
   sweat. Problems arise when you want to get a string and return a
   string, you also have to use complex segment declaration. And you have
   to DGROUP both _BSS and _DATA. You who know what im talking about, you
   can easily do it. You who doesn't, well, not my problem.
   
   Microsoft wont officially support ARRAY passing for QB4.5, and I wont
   either, but if you want to know how its done, just tinker around abit.
   Its really easy. Hint: myarray:word, myarray will point to header.
   
                           By Sten Daniel Sørsdal
                                      
                                Back 2 Top 
     _________________________________________________________________
                                      
                            PlatForm Engines 101
                                      
   To tell ya the truth, platform engines are really easy to code. A lot
   easier than what i thought it'd be. To start out, you use a regular
   pixel engine. Yep, that's right, a regular pixel engine. If you don't
   know what that is, it's basically a tile engine that can scroll using
   pixels. And if you don't know what a tile engine is, then you really
   don't need to read this, not to be mean or anything, but learn to
   create a tile engine, then I'll be glad to help with a pixel engine.
   First off, to create the pixel engine, start off with a tile engine,
   and add tile offsets. So lets say you have map offsets; Xoffset,
   Yoffset Those are our map locations for the upper lefthand tile. The
   tile engine would set the screen up like so:
   
 _ _ _ _ _ _ _ _ _
|a|_|_|_|_|_|_|_|_|  If Xoffset and Yoffset = 1 then the block "a" is
|_|_|_|_|_|_|_|_|_|  where xoffset and yoffset are. Easy huh?
|_|_|_|_|_|_|_|_|_|
|_|_|_|_|_|_|_|_|_|  Adding Tile offsets are just as easy. Lets say
|_|_|_|_|_|_|_|_|_|  tiles are 16x16, your basic tile. When scrolling
|_|_|_|_|_|_|_|_|_|  you add to the offset until it reaches 16 segments
|_|_|_|_|_|_|_|_|_|  then set it back to 0, and adding 1 to the map offset.

   Sounds simple enough right? In laymans terms:
   
  TileX = 0

  SUB ScrollRight
    TileX = TileX + 1        'TileX is the tile offset for the X coords.
    IF TileX > 15 THEN       'starting TileX at 0 and adding 16 gives you 15
      TileX = 0              'put TileX back on 0 (default for next tile)
      Xoffset = Xoffset + 1  'move the map X coords over 1
    END IF
  END SUB

   I told you it was easy. Adding detection is pretty simple too, just
   check the Tile offsets against the map coords, and see if the tile is
   walkable.
   
   Yea, i know, this isn't REAL pixel by pixel, but i never said it was.
   =)
   
   Also, you may want to use a PUT routine that has clipping
   capabilities, which lets you place a tile half on the screen, most
   libraries allow this, i think, i don't use any except Qb13h. And i
   KNOW it does clipping. Ok, on to the platform.
   
   Platforms are the same, except you don't need to scroll up and down,
   or, at least you really don't need to. So maps can be longer. The way
   i do maps:
   
DIM SHARED map%(1, 200, 15)

   This allows me to have a 2 layer map system that is 200 tiles long and
   15 tiles high. Like i said, you don't NEED to scroll up and down,
   though you can if ya want.
   
   It's the same as what i just went thru above, using a pixel engine,
   just only able to scroll left and right. Only difference in them is
   the graphics that you use, instead of an RPG tileset, you'd use a side
   tile set. With cliffs and holes and things inside it.
   
   When placing a character into the engine, you just supply an X and Y
   coord for him to start. Usually on a ground level. While scrolling and
   finding where the character is, you check for map location, collision
   detection is better terms. I'm sure you are all familiar with it. You
   check the X and Y locations against the FIRST layer on the map, if
   it's a tile you can't walk on, the player can't move. If he CAN walk
   on it, then of course he can go across it. Also you would need to
   check above and below the player to check for holes and cliffs.
   
IF map%(0, PlayerX, PlayerY + 1) < 0 THEN 'check below player for
        MakePlayerFall                          'nonwalkable tile
END IF

   It's simple to implement, well, simple to me, i know, and I'm tryin to
   explain it the best i can.
   
   One thing i forgot to mention. You will need to add character tile
   offsets that tell if the character is between tiles. It works the same
   way as the tile offsets. When scrolling right, you'd add 1 to the
   PlayerXTileOffset.
   
   After PlayerXTileOffset > 15 then you'd add 1 to the PlayerX coord,
   moving the player along. This is a MUCH easier way to compare map
   locations with the player coords. It saves lots of time and trouble
   later.
   
   When making the player jump, you want to use tile detection again,
   checking 1 tile above the player while he is moving up, then when he
   starts coming down, you check below him, all the while checking the 1
   tile in front of the direction he is facing. Hope that wasn't too
   confusing. (Any questions just email me =)
   
   When showing the map, you just show the first layer, then show the
   player, then place the top map layer over top, so you get a "walk
   behind" effect. This effect adds really great looks to a good engine.
   While placing the second layer, to speed things up, make sure that you
   have a tile that is not placed. So that you won't need to go thru the
   whole loop of placing tiles.
   
   Say tile #17 isn't goin to get placed for the second layer, I would do
   something like:
   
DIM SHARED tiles(200, 5)
DIM SHARED map%(1, 200, 15)

SUB ShowMap
x = 0: y = 0
FOR b = Yoffset TO Yoffset + 13        'places 13 (16x16) rows on the screen
  FOR a = Xoffset TO xoffset + 20      'places 20 (16x16) cols on the screen
    Puttile (x, y), tiles(0, map%(0, a, b))  'routine for placing tiles
    x = x + 16                         'moves location over 16 pixels
  NEXT a
  x = 0: y = y + 16                    'starts new row
NEXT b

PutPlayer

x = 0: y = 0
FOR b = Yoffset TO Yoffset + 13        'places 13 (16x16) rows on the screen
  FOR a = Xoffset TO xoffset + 20      'places 20 (16x16) cols on the screen
    IF map%(1, a, b) <> 17 THEN        '17 being the tile not going to get
                                        'placed
      Puttile (x, y), tiles(0, map%(1, a, b))  'routine for placing tiles
    END IF
    x = x + 16                         'moves location over 16 pixels
  NEXT a
  x = 0: y = y + 16                    'starts new row
NEXT b

END SUB

   That's usually what my map show sub looks like. Placing the first
   layer of the map (map%(0, x, y)) and then placing the player
   (PutPlayer), then placing the second layer of the map (map%(1, x ,
   y)). Simple right? I hope so. Hopefully this article made sense, if
   not, email me and i will try to explain it a bit more in more detail.
   Thanks for your time!
   
                                [sshot.gif]
                                      
                                By Necrolyte
                                      
                                Back 2 Top 
     _________________________________________________________________
                                      
         QUICKBASIC MAGAZINES: NO MORE, PLEASE! STOP THE INSANITY!
                                      
   (DISCLAIMER: I'm writing this to express that I think there should be
   only one mag, not so many. I'm not insulting anyone who makes a mag,
   cause it is hard work, and I respect you. I just think someone should
   establish a standard. So please don't get pissed at me :-)
   
  Intro
  
   Quick! Look to your left! It's a QB Mag! Look above you! It's a QB
   DiskMag! Ahh! To the right! Another mag! Now that your attention has
   been captured, lets continue.
   
  Why?
  
   Why do we need 2 million QB mags? Its stupid. Which one do I read to
   get the latest and greatest info? Which one has the best project
   reviewers? No one reads 4 newspapers a day so they won't miss
   anything, and no one has to. Most of the QB mags and diskmags have the
   same news, and some even rip others content. 12 mags all with the same
   content doesn't make any sense. So, here is an idea, JUST HAVE ONE,
   PLEASE!
   
  Two or three is all we need
  
   Why not just have 1 or 2 mags? If we had two then we could have one
   mag and one diskmag. One for people to read quickly and easily, and
   one for people to download and enjoy. Also, another idea is for one
   that is emailed instead of HTML or download(Tek is already doin this
   with The QB Gazette, which is cool).I beg for this option!
   
  A Standard
  
   One QB mag should be the main mag that is read and written by the QB
   community as a whole. This would be easier for readers and effective.
   It could be hosted on one of the more popular QB sites. This would
   eliminate ALL of the problems which have occured because of the mass
   number of QB mags.
   
  Let's Count...
  
   Lemme count the number of QB mags and Diskmags just from memory, lets
   see, there is Razor DiskMag, the late QBTM, QB on Acid, The QB Times,
   The QB Gazette, and another nameless QB diskmag that is just
   surfacing. And those are only the ones I can think of right now at
   almost 12:43 AM. Who the hell knows how many more there are? Now, lets
   take a second to think about what the hell is wrong with this picture.
   You thinking? Good. Lets see, there are TOO many mags and diskmags,
   almost all of them have the same content, the people who write for one
   of the mags usually writes for others too therfore dishing out the
   SAME content, and finally, IT'S FUCKING RIDICULOUS!
   
  Conclusion
  
   Well, as you can see, I hate having so many QB mags and diskmags. Its
   nonsense. Just have one no frills mag that takes care of it all, then
   the editors of the other mags can take a break and have a shower.
   Thanks for reading this, and be sure to submit any ideas for rants to
   brandon@nssoft.cjb.net!
   
                                  By Nova
                                      
                                Back 2 Top 
     _________________________________________________________________
                                      
            Beginner's Tutorials: Chapter 1 - Beginning Commands
                                      
    This is a set of tutorials that will come out 1 each issue of QBoA.
    They are aimed to teach you how to use QB from the beginning. I will
   assume you have QBasic and know your way around it. Today we will talk
   about the commands PRINT, CLS, and INPUT. I will also introduce you to
                                 variables.
   ______________________________________________________________________
                                      
                                   PRINT
                                      
   The PRINT command does what it says, it PRINTs. What does it PRINT to
    you ask? Not the printer, but the screen. It simply PRINTs the words
   you specify to the screen. The syntax for PRINT is PRINT "". Put what
            you want to show up on the screen inside the quotes.
                                      
                                      
                            PRINT "Hello World!"
                                      
                                Example Code
                                      
                                    CLS
                                      
   What happens when you write a program, run it, then add some more code
   to it and run it again? You still see what was on the screen the last
      time you ran it. To fix this problem put the command CLS in your
    program. CLS stands for CLear Screen. It does what it stands for, it
     clears the entire screen. The syntax for this is, of course, CLS.
                                      
                                      
                                 VARIABLES
                                      
     Variables are used to store information in your computers memory.
    Think of them as storage boxes in your computer. Variables are VERY
      useful. They are almost ALWAYS used in a program. There are five
   different types of variables. They are string, integer, long integer,
     single precision, and double precision. Different symbols must be
   placed at the end of variable names so QB knows what type of variable
    it is working with. Strings use $, integers use %, long integers use
    &, single precision uses !, and double precision uses #. The type of
    variables you will use most often are strings and integers. Strings
     store words, integers store numbers. To declare a variable just do
   this: ExampleVariable$ = "hello". That is a string variable(notice the
      $) that is now storing the word "hello". When declaring a string
      variable make sure to put its value inside quotes. To declare an
     integer variable just do this: IntegerVariable = 8. Notice that I
    didn't have a % at the end of the variable name. That's because with
   integers you don't have to have one. If you don't put a symbol at the
         end of the variable name, QB makes it integer by default.
                                      
                                      
                               name$ = "Bob"
                              score% = "1500"
                                 age = "15"
                                      
                                Example Code
                                      
                                   INPUT
                                      
    Programs are no good if you can't accept input from the user, right?
   Well that is what this command does. Judging by its name, you probably
              knew that already. The syntax for INPUT is this:
    INPUT; "What is your name" (, or ;) variable. Lets break this down.
    First, you have the command. Next is a semicolon, which is optional.
     The semicolon right after INPUT keeps the cursor on the same line
   after the user presses enter. Next is prompt string. It is what shows
        up when the INPUT code executes. Next is either a comma or a
    semicolon. If you put a semicolon then a question mark appears after
   the prompt string. If you put a comma, then no question mark appears.
   Last is the variable you want to store the users input in. Now, about
   the Prompt String, some might not understand it, so I will talk about
   it. If your prompt string is "What is your name" then the words "What
   is your name" will appear on the screen and the program will wait for
                       the user to input the answer.
                                      
                                      
                INPUT "Hello. What is your name"; usersname$
                   INPUT "Enter your Zip Code: ", zipcode
                       INPUT; "Enter your age: ", age
                                      
                                Example Code
                                      
                             PRINTING VARIABLES
                                      
   So, you used the input command and stored some data from the user in a
   variable, but what good is the data if you can't display it? Well you
   can using the PRINT command. It's VERY simple, heres the syntax: PRINT
     variable. You just type PRINT then the variable name, easy stuff.
             Don't forget to include the variable type symbol.
                                      
                                      
                             PRINT playername$
                                 PRINT age
                                PRINT score%
                              PRINT enemyname$
                                      
                                Example Code
                                      
                               YOUR HOMEWORK
                                      
    Your homework is to make a program that clears the screen, asks the
     user for his/her name, stores it in a variable, and prints out put
              his/her name on the screen. See you next issue!
                                      
                                      
                 Written By: Nova - brandon@nssoft.cjb.net
                                      
                                      
                                      
                                Back 2 Top 
     _________________________________________________________________
                                      
                      Implicit Surface Polygonization
                                      
   This article, originally an e-mail to tek_hed and some others, will
   describe a method for polygonizing implicit surfaces. Metaballs are an
   example of these: the surface is not defined explicitly (as in
   polygons), or parametrically (as in spline grids), but rather, well,
   implicitly. Basically, you have a function f(x,y,z) which is 0 for any
   point on a closed surface, negative on the "inside" of that surface,
   and positive on the "outside".
   
   Now, to polygonize it, you create an array of points at an arbitrary
   resolution (100x100x25 would do fine in most situations), and evaluate
   the function for every point.
   
   Then, you connect all the points with the ones exactly 1 unit away,
   creating a gridwork between these points. Every one of those
   connections that crosses through the texture (ie, one endpoint has a
   different sign than the other), you do a binary search (or just
   approximate by averaging) to find a much closer point to the surface,
   and you "attach" that point to the two endpoints.
   
   Then, you go through all the points again, and for every one that has
   3 attached points that are NOT coaxial (ie, one is offset only by X,
   one only by Y and one only by Z), you generate a poly connecting those
   points.
   
   You cover all combinations of 3 points that are not coaxial that are
   connected to the same grid point, and when you're done, you have a
   polygonal representation of the implicitly defined surface (which
   could be a metaball system or whatever).
   
   To refine the surface, look at every edge of the polys and find the
   angle between the polys on each side of the edge. Sort the edges by
   this angle, and resample the ones with angles exceeding a given
   threshold using a finer grid (ie, the same grid over a smaller
   volume).
   
   There ya go =D
   
                     By logiclrd at http://logiclrd.cx
                                      
                                Back 2 Top 
     _________________________________________________________________
                                      
                  Infix -> ASM convertor plan, by logiclrd
                                      
   For every sum-of-terms, reorder it so that the longest terms come
   first, e.g.:
   
1 + 2*3 -> 2*3 + 1
1 + (4/2 - 6*8/3) - 3*4 -> (-6*8/3 + 4/2) - 3*4 + 1

   Then, switch the order of dividends with their divisors (the reason
   for this will become clear later), e.g.:
   
4/3 -> 3/4
(6+3)/(2*x) -> (2*x)/(6+3)

   Look for terms in which the non-variable factors (ie, the
   coefficients) can be simplified, e.g.:
   
2*x/4 -> x/2
3*6 -> 18

   Now convert the string to an expression tree by recursively selecting
   the last operation (by order of operations) of the current substring
   to be the new subtree's head. e.g.:
   
4*2+6 ->    +     ->   +
           / \        / \
         4*2  6      *   6
                    / \
                   4   2

   Swap the left and right children of any node whose left child is a
   numeric constant and whose right child is not, e.g.:
   
      +     ->     +
     / \          / \
    6   *        *   6
       / \      / \
      3   x    x   3

   Swap the left and right children of any node whose left child is a
   greater power of two than its right child, e.g.:
   
      +     ->     +
     / \          / \
    8   *        *   8
       / \      / \
      4   x    x   4

   Swap the left and right children of any division node whose _LEFT_
   child is a power of two (since we changed 4/3 to 3/4), and take the
   logarithm base 2 of the new right side, changing the node into a
   "shift right" operation:
   
( x/8 -> 8/x -> )  '/'  ->  shift right
                   / \          / \
                  8   x        x   8

   Now, parse the tree in postfix order to generate an RPN expression,
   e.g.:
   
    +     -> (x, 4, *, 8, +)
   / \
  *   8
 / \
x   4

   We're halfway there!
   
   Replace any constant followed by a + or - operator with a special code
   "add ", e.g.:
   
(x, 4, *, 8, +) -> (x, 4, *, add 8)

   Replace any constant followed by a shift or bitwise operator into a
   single list entry in a similar manner, e.g.:
   
(x, 3, &, 2, <<) -> (x, and 3, shift left 2)

   Replace any power of two followed by a * operator with a special code
   "shift left" e.g.:
   
(x, 4, *) -> (x, shift left 2)

DO

   Replace any "shift left" operation followed by a "shift right"
   operation with the corresponding single shift, e.g.:
   
 (x, shift left 3, shift right 1, shift left 4) -> (x, shift left 2, shift left
 4)

   Replace any "shift left/right" operation followed by another similar
   "shift left/right" operation with the corresponding single shift,
   e.g.:
   
 (x, shift left 2, shift left 3, shift right 1, shift right 2) -> (x, shift lef
t 5, shift right 3)

LOOP WHILE (changes made)

   Here's the part that'll most likely require the most code: parsing the
   RPN string into ASM, keeping track of what registers are which stack
   entries. Treat the registers as though they were the RPN stack, using
   MOV EAX,[x] instead of PUSH [x]. This way, all PUSHes and POPs are
   virtual (unless you run out of registers, in which case you are forced
   to PUSH one of your registers anyway -- this is unlikely, though,
   unless you're dealing with a maniac of a coder!), and must be kept
   track of within your conversion routine. If you have an item which is
   implicated in a subtraction or addition and there is a multiplication
   or a division in between the term and it's operator (i.e., the '*'
   between '2' and '+' in (4, 2, 3, *, +)), then avoid using EAX or EDX
   for that term. If there is an item which has only shifts, special
   additions and special subtractions (not '+' or '-', just 'add 3'-type
   items) between it and the next multiplication or division, place that
   term into EAX. Keep in mind that modulus values can only be placed
   into EDX, while the actual division to be performed implicates EAX.
   These 'in-between' checks can be performed by going through the RPN
   list, keeping track of the stack height at every point. Also, watch
   out for changes in the order of stack variables. These are pretty much
   guaranteed to be the same for every operation of a given type. I've
   documented them below, to give examples. For divisions, divide EAX by
   the second-to-topmost item on the stack (this is why we changed 4/3 to
   3/4: 3/4 becomes 3,4,/, 4 goes into EAX, and we can do DIV EBX). E.g.:
   
(x, y, z, add 4, *, +)

   would become:
   
MOV EBX, [x]   ; because there is a '*' between 'x' and its '+'
MOV ECX, [y]   ; 'z' is between 'y' and '*', and ECX is next available register
MOV EAX, [z]   ; only 'add 4' between 'z' and '*'
ADD EAX, 4     ; here's the special 'add 4' routine
MUL ECX        ; before operation, stack is: EBX->ECX->EAX, after: EBX->EAX
ADD EAX, EBX   ; before operation, stack is: EBX->EAX, after: EAX

   And finally, if the resulting value is not in EAX, move it there
   (unless you have intelligent condition parsing code). If your last
   operation is a commutative operation which uses EAX as an operand but
   not as the target, switch the operands around, e.g.:
   
ADD EBX,EAX
MOV EAX,EBX

   would become:
   
ADD EAX,EBX

   thereby avoiding copying the value back into EAX.
   
   You're done! (but don't forget to keep track of which registers were
   destroyed, and don't forget to PUSH all the registers with values you
   need when doing function calls)
   
   By this method, this expression:
   
(x / 8) & 63 + 64 * ((y / 8) & 63

   would become:
   
MOV EAX,[y]
SHR EAX,3
AND EAX,63
SHL EAX,6
MOV EBX,[x]
SHR EBX,3
AND EBX,63
ADD EAX,EBX

   which, I'm sure you'll agree, is pretty damn good output.
   
                                By logiclrd
                                      
                                Back 2 Top 
     _________________________________________________________________
                                      
                           An Attack On Polfalk?
                                      
   Here's Polfalk's way of creating an RPG (in QBasic), and a direct
   quotation from LordQB's WebBoard that shows his total stupidity.
   LordQB's QuickBasic RPG site is at
   http://members.xoom.com/qbasic_rpgs/
   
   Polfalk
   How to make a REAL QBasic Rpg!!
   Sun Dec 19 12:35:32 1999
   
   Take some ripped graphic, use PLAY instead of MIDI and if someone
   complaints just say "At least it works on every computer". Make it so
   slow that everyone thinks it's P*P scroller, if you need some dialog
   (just in case), use PRINT.
   
   And, finally, if you must (and only if you must!!) make a storyline.
   Do not implented though, just say "It will be implented in the next
   demo" and never release "the next demo".
   
   --Polfalk
   
   btw, this is how I make my Rpgs, if you have any complaints... well,
   that's not my problem.
   
   Apparently, he proved this method by actually STEALING graphics from
   DarkDread's EGA color game, Secret of Cooey 2. My sources revealed to
   me later that he changed this, as this is embarassing and that is
   exactly why I pointed this out! It's embarassing! I don't think
   Polfalk would need any dialogue in his games due to the fact he makes
   piles of spelling errors which is demonstrated in his above post on
   LordQB's WebBoard. And he says, and I quote "btw, this is how I make
   my Rpgs, if you have any complaints... well, that's not my problem." .
   Apparently, this will be his problem since I'm publicly embarassing
   him and pointing him out to the QB Community as a fraud and a dirty
   bastard because he steals graphics of hardworking programmers and
   makes crappy games, which in turn makes the game which the graphics
   were stolen off of, look worse! I think you owe DarkDread a sincere,
   public, begging-for-forgiveness apology! And I think we all agree! YOU
   SUCK POLFALK, WORSE THAN THE PHANTOM LIGHTING VACUUM! AND IT HAS
   DUAL-CYCLONIC ACTION, EASY DISPOSING BINS, AND A UNIQUE STAIR-HUGGER
   DESIGN! Go scamper away, and produce an RPG worth looking at! Then,
   maybe you won't get large articles making fun of you!
   
   Article written by MAjIkO!
   
   By the way Polfalk, the opinions expressed in this article are solely
   mine, and a few others. We hate you, go away!
   
   My site is currently located at http://majiko.logiclrd.cx/, and will
   be moving to a better server soon, but the files and a nice archive
   will be kept there! So hang tight and hang ten!
   
                                 By Majiko
                                      
                                Back 2 Top 
     _________________________________________________________________
                                      
                         Game Review: Killers Remix
                                      
   Ahh, another game by Nekrophidius. Will it live up to the standards of
    his other games? Will the download size for this game be the size of
               the download for WOS? Stay tuned and find out!
   ______________________________________________________________________
                                      
                                      
                                      
                            Parental Advisories?
                                      
                               [warning.gif]
                                      
                         "A p0rn game? Not quite."
                                      
   The first thing you see when you start the game is this parental
   advisory  screen. A p0rn game? Not quite. The only close to p0rn
   thing  I see in here is short skirts. Oh yeah, and the girl wearing
   only a snake and shoes *cough*. Graphic violence? Not yet, only
   violent spin kicks to the lower jaw in the demo.
   
                                      
                                      
                                The Graphics
                                      
   Ok, lemme quote from the exit screen of the program, "...We'll prolly
    just keep rippin the gfx from commercial games =)". Heh. I asked Nek
    about this and he confirmed he ripped them. He did however make the
    opening screens, the character's faces, and the logos. He also said
   that the backgrounds were public domain. The opening screens look good
    and the faces are also good. The graphics are very SNESish, which I
    happen to LOVE. It reminds of of all those summer days spent playing
      Street Fighter 2. The bloody sword health bars are cool, and the
    flashing when you are low on health helps you know when you need to
                       start fighting harder or die.
                                      
                               [screen1.gif]
                     "The graphics are very SNESish..."
                                      
                                  Gameplay
                                      
    As I said above, this is a very SNES style fighter. Most QB fighters
    are stick fighters, so naturally the gameplay is going to better for
     this game than others because of full figures. This is a demo, so
   naturally everything isn't finished. The only two things you can do so
     far are high punch and high kick. The objective is the same as all
     other fighters: beat your opponet down to win. Nek has planned out
       VERY bloody scenes and GRUESOME deaths, heh, I like that. Your
   opponets are fairly smart, although I found out that if you just high
         kick them every time thet come close, you can easily win.
                                      
                                      
                                The Controls
                                      
   As I said above the only actions in this demo are high punch and high
    kick. The keys for these actions are well place, being ALT for high
    kick and CTRL for high punch, no A for kick and shit like that. The
   controls to move your character are also well placed, being the arrow
   keys. It is very easy to use these controls together to play the game.
   They are all near each other so you won't have to stretch your hand. I
   had no problems with control while playing Killers Remix. Bottom line:
      controlling is good so far, just don't screw it up later Nek :p
                                      
                                      
                                   Sound
                                      
       Sound is always important in a game. Sound gives the game more
   meaning. Kicking a guy square in the face just isn't tha same without
    some fast paced music to go with it. The game has 16 music tracks in
      the demo, with double that amount planned for the final product.
                                      
                                      
                                  Overall
                                      
   Overall Killers Remix is a good, solid game. I found no bugs in it at
     all. Control is easy. The only problem I found (there are probably
   more) in KR is that the animation is a little too fast when you punch,
      kick, etc. Even for a demo, this a good game. I really like the
         SNESish feel of the game, takes me back to days gone past.
                                      
                                [title.gif]
                                      
                 Written By: Nova - brandon@nssoft.cjb.net
                                      
                                Back 2 Top 
     _________________________________________________________________
                                      
                        Product Review: QBP's Engine
                                      
   QbProgger recently sent me a copy of his RPG engine, and asked for a
   review of it. So, I agreed, and here's the results.
   
  The Good
  
   This RPG engine is VERY fast. It is a full p*p scrolling engine
   (although he coded it to move at 16 pixel increments, giving the
   appearance of a t*p). 8-way movement is present, which is nice. What
   really amazed me was the amount of onscreen moving NPCs...they were
   all over the place! They all looked the same though (two NPCs, a guy
   and a girl) but damn, they were everywhere.
   
  The Bad
  
   Although this is anything but your typical RPG scrolling demo, it's
   still just a scrollie. There is no game present. The movement is a
   little whacked, the character gets stuck a lot and there's no way of
   telling (due to the simplistic nature of the graphics) where the hell
   you are going. It does appear QBP's scripting engine isn't in place
   yet either, since the NPCs were all very silent (kind of annoying!
   ack)
   
  The Skinny
  
   Apply a game to this, and you have a masterpiece. Until that time,
   it's just a scrollie. Although a very impressive scrollie...but still
   just a scrollie. I know QBP's spent years trying to perfect the RPG
   engine, and you can certainly see the experience in this one, but
   there's more to a game than the engine...now it's time to add the
   rest.
   
                              By Nekrophidius
                                      
                                Back 2 Top 
     _________________________________________________________________
                                      
                          Music Review: Syraphage
                                      
   Liquidex, the chief figure behind the Syraphage project, recently sent
   QBoA several pieces of music from the upcoming Build 5 of Syraphage,
   so that we may review the soundtracks. Of the three submitted, only
   two shall be reviewed here, since the first piece (the title) will not
   be used in the game anyways. So, here we go...
   
  Syraphage: Battle
  
   This is a semi-fast tune, with a driving beat and some interesting
   synths. You can definately hear a technoesque influence in this piece,
   however, the heavy guitar synth was very cool as well. The only real
   problem with this piece is that most of the channels are centered, and
   this tends to kill the quality in anything but Modplug Player. You can
   really get the sense of urgency in this piece, it will fit very well
   into a battle scenario.
   
  Syraphage: Guilden
  
   Wow...talk about contrast in styles. This is a very nice acoustic
   guitar piece. Flutes in the background, a nice rhythm, and an
   interesting progression. The theme tends to lend itself to redundancy
   however, as there's never really any break from the same progression
   of note structure. In a game you'd probably never notice this however.
   This piece will be used in towns, according to Liquidex.
   
   So there you have it. For the record, these pieces will be played
   through Alphx's own LiquidGL module player when Build 5 is released.
   
                              By Nekrophidius
                                      
                                Back 2 Top 
     _________________________________________________________________
                                      
   Interview with JQB45 (Jeff Crawford) on Rapid BASIC, formerly known as
                                   NextQB
                                      
   This really seems to be the next best thing on the market. In this
   interview with JQB45, i found out that there are great features
   involved in this compiler. It will be totally 100% compatible with
   QB4.5, which would make it very easy to use. The first demo should be
   out around Jan 20-25th for public use. Their are a only a handful of
   supported keywords in the first demo. This list can be found at Rapid
   BASIC's site under News.
   
   According to Jeff, Rapid BASIC translates BASIC to highly optimized
   Assembly, hence the name "Rapid BASIC." Jeff also states that
   executables created by Rapid BASIC seem to be 30 to 50 times smaller
   than the exact same source compiled by the QB45 compiler. This is
   great, seemin most of MicroSoft's products are TOTALLY bloated out of
   proportion. Speed for Rapid BASIC hasn't been determined yet, though
   Jeff says it should increase 30% to 50%. Also a good thing, that IS
   what everyone is looking for right? SPEED!!!
   
   Quoting Jeff, "Long integers have been increased in speed nearly 100
   times over. Math routines use the FPU instead of emulation and should
   produce very nice results indeed." Doesn't this sound astounding? He
   also has added bitshift operators, along with true inline assembly,
   using an ASM...END ASM block. This will defeat the purpose of using
   Call Absolute and Call Interrupt. Inline ASM should produce a huge
   increase in speed also. It should also cut down on library usage and
   pointing programmers in the way of ASM, so their programs will be
   faster.
   
   For those of you wondering if you will still be able to use QuickBASIC
   libraries...yes, all current libraries are 100% compatible. This is
   also great, i mean, c'mon! Smaller EXE's and faster code, PLUS the use
   of libraries!? I'm amazed....
   
   As for an IDE, Jeff says that several text editors with syntax
   highlighting and all the convience features are being developed. Maybe
   he should talk to War_Lord? (War_Lord is creating WinQB). These IDE's
   being developed my not be ready by the first release of RB's Demo.
   Don't worry, you can still use Rapid BASIC! You should be able to use
   QB45's IDE, or any other text editor like NotePad.
   
   For any other information not talked about, or if you want to see more
   information (if this inteview hasn't convinced you this WILL be a
   great compiler) you can goto http://24.26.150.46.
   
   'till the next article i do, 
   
                                 Necrolyte
                                      
                                Back 2 Top 
     _________________________________________________________________
                                      
                             QUOTE OF THE MONTH
                                      
   This issue's quote comes from an unknown newbie known only as
   
                                    TLQ
                                      
   "I'm making $1000 in January of 2000 doing stuff with QB, so I think
   if I wasn't good at it, they wouldn't pay me so much for my services.
   It is only maps that I'm having troubles with."
   
   This person posted this little wonder on LordQB's QBRPGs message
   board. After several posts proving his/her true ignorance in coding
   and trying to get other people to do his/her work for them, they
   decided to offer this in response to an accusation of rookieism. I do
   believe there's an old saying that goes sorta like this..."It's better
   to close your mouth and to be thought a fool, than to open it and
   remove all doubt."
   
                                Back 2 Top 
     _________________________________________________________________
                                      
                                THE GALLERY
                                      
   This time we have two games featured in the Gallery, since last time
   we didn't have ANY. So, the first one was submitted by xms, who is
   working on the game Cataclysm Eve (we reviewed the alpha earlier in
   the QBoA series). He's got some new screenshots, and take a look!
   
                                [attack.gif]
                                      
                               [field10.gif]
                                      
                                [field5.gif]
                                      
                                 [menu.gif]
                                      
                                [npcs2.gif]
                                      
                               [LeftTown.gif]
                                      
                               [castle1.gif]
                                      
     The second Gallery entry is a single pic, however, it looks mighty
     tasty. This is another Tetris clone, but this one's being coded by
    none other than "Zip Person" (that's the best name we could come up
                  with! heheh) and is looking nice so far.
                                      
                               [tetris3.gif]
                                      
   Now, what is this picture? According to rumour mill, this is actually
    a shot from the upcoming super-game SubShock...online capabilities?
                     Can it be true? See for yourself!
                                      
                               [winserv1.jpg]
                                      
                                Back 2 Top 
     _________________________________________________________________
                                      
                             Coding Info Block
                                      
   To get the VESA hi-resolution modes, you'd do this:
   
mov ax, 4F02h
mov bx, mode
int 10h

   Where mode is a hex number between 100h and 164h, Goto:
   http://www.ctyme.com/intr/RB-0274.HTM for a list of most of the vesa
   modes. As for the rest of the lesser known vesa modes, here they are:
   
131h 320x240x256
132h 320x240x32K
133h 320x240x64K
134h 320x240x16M
141h 400x300x256
142h 400x300x32K
143h 400x300x64K
144h 400x300x16M
151h 512x384x256
152h 512x384x32K
153h 512x384x64K
154h 512x384x16M
161h 1152x864x256
162h 1152x864x32K
163h 1152x864x64K
164h 1152x864x16M

   I'm not sure yet, but there might be screen modes after 164h.
   
                                  By QB_AL
                                      
                                Back 2 Top 
     _________________________________________________________________
                                      
                             Neat Code Example
                                      
                           Super-Fast Pure QB PUT
                                      
DEFINT A-Z
DECLARE SUB precalc ()
DECLARE SUB demo ()
DECLARE SUB tput (sprite%(), x%, y%)
'====================================================
'  NEGPOKE3: 16x16 Screen 13 Clipped Sprite PUT demo
'  Copyright 1999 Toshihiro Horie.
'====================================================

'  Best Timings (compiled on Cyrix 6x86 100Mhz):
'     NEGPOKE3: 27191 sprites/second (my routine)
'     SPDTESTO: 17035 sprites/second (Pasco's lib)
'
' This negative segment and poke offset idea came from the
' distant past, when I was using Applesoft BASIC.  BASIC
' used signed integers even then, and POKEing to negative
' positions meant writing to the memory address at
' the unsigned version of the binary representation of
' the negative address.

DIM SHARED pokeseg(200)
demo

SUB demo

precalc

'draw and save a sample sprite
DIM sprite(130)
SCREEN 13
FOR x = 0 TO 15
    FOR y = 0 TO 15
        PSET (x, y), x + y + 100
    NEXT y
NEXT x

' save into normal QB sprite array
GET (0, 0)-(15, 15), sprite

t1! = TIMER
'main test loop (do not make the max value 32767)
FOR iter = -32768 TO 32766
    tput sprite(), RND * 320, RND * 200
NEXT iter
t2! = TIMER
sps! = 65535 / (t2! - t1!)

SCREEN 0: WIDTH 80: CLS
PRINT sps!; "16x16 sprites/second"
END SUB

SUB precalc
'precalculates the correct starting segment
'for each scanline.  This way we get
'NO overflows even if we use all integer calc.

pokeseg(0) = -24576
FOR yp = 1 TO 199
    pokeseg(yp) = pokeseg(yp - 1) + 20
NEXT yp
END SUB

SUB tput (sprite(), x, y)
'16x16 clipping sprite PUT routine with no multiplies in sight!
'  this assumes the GET sprite() array is ready for use,
'  and that the given x, y coordinates are within screen range.

'QB4.5's PUT is faster than looped POKE for in-screen blits
IF x < 304 AND y < 184 THEN PUT (x, y), sprite, PSET: EXIT SUB

'xd is the visible width of the sprite
'yd is the visible height of the sprite
xd = 319 - x
yd = 199 - y
IF xd > 15 THEN xd = 15
IF yd > 15 THEN yd = 15


s = VARSEG(sprite(0))
r = 4 'array data start = 0 + (4 bytes of header skipped)

'This uses the loop unrolling optimization
'which also gets rid of extra segment switching.
'Of course, all those peek/pokes could easily be
'replaced by a simple memcopy function in asm,
'but this was for a Pure QB speed competition.

'There are rumors that the internal function
'B$ASSN may be abused as memcopy routine, but
'I decided against using it.

FOR dy = 0 TO yd
    yseg = pokeseg(dy + y)
    SELECT CASE xd
        CASE 0
            DEF SEG = s
            z0 = PEEK(r)
            DEF SEG = yseg
            POKE x, z0
        CASE 1
            DEF SEG = s
            z0 = PEEK(r)
            z1 = PEEK(r + 1)
            DEF SEG = yseg
            POKE x, z0
            POKE x + 1, z1
        CASE 2
            DEF SEG = s
            z0 = PEEK(r)
            z1 = PEEK(r + 1)
            z2 = PEEK(r + 2)
            DEF SEG = yseg
            POKE x, z0
            POKE x + 1, z1
            POKE x + 2, z2
        CASE 3
            DEF SEG = s
            z0 = PEEK(r)
            z1 = PEEK(r + 1)
            z2 = PEEK(r + 2)
            z3 = PEEK(r + 3)
            DEF SEG = yseg
            POKE x, z0
            POKE x + 1, z1
            POKE x + 2, z2
            POKE x + 3, z3
        CASE 4
            DEF SEG = s
            z0 = PEEK(r)
            z1 = PEEK(r + 1)
            z2 = PEEK(r + 2)
            z3 = PEEK(r + 3)
            z4 = PEEK(r + 4)
            DEF SEG = yseg
            POKE x, z0
            POKE x + 1, z1
            POKE x + 2, z2
            POKE x + 3, z3
            POKE x + 4, z4
        CASE 5
            DEF SEG = s
            z0 = PEEK(r)
            z1 = PEEK(r + 1)
            z2 = PEEK(r + 2)
            z3 = PEEK(r + 3)
            z4 = PEEK(r + 4)
            z5 = PEEK(r + 5)
            DEF SEG = yseg
            POKE x, z0
            POKE x + 1, z1
            POKE x + 2, z2
            POKE x + 3, z3
            POKE x + 4, z4
            POKE x + 5, z4
        CASE 6
            DEF SEG = s
            z0 = PEEK(r)
            z1 = PEEK(r + 1)
            z2 = PEEK(r + 2)
            z3 = PEEK(r + 3)
            z4 = PEEK(r + 4)
            z5 = PEEK(r + 5)
            z6 = PEEK(r + 6)
            DEF SEG = yseg
            POKE x, z0
            POKE x + 1, z1
            POKE x + 2, z2
            POKE x + 3, z3
            POKE x + 4, z4
            POKE x + 5, z5
            POKE x + 6, z6
        CASE 7
            DEF SEG = s
            z0 = PEEK(r)
            z1 = PEEK(r + 1)
            z2 = PEEK(r + 2)
            z3 = PEEK(r + 3)
            z4 = PEEK(r + 4)
            z5 = PEEK(r + 5)
            z6 = PEEK(r + 6)
            z7 = PEEK(r + 7)
            DEF SEG = yseg
            POKE x, z0
            POKE x + 1, z1
            POKE x + 2, z2
            POKE x + 3, z3
            POKE x + 4, z4
            POKE x + 5, z5
            POKE x + 6, z6
            POKE x + 7, z7
        CASE 8
            DEF SEG = s
            z0 = PEEK(r)
            z1 = PEEK(r + 1)
            z2 = PEEK(r + 2)
            z3 = PEEK(r + 3)
            z4 = PEEK(r + 4)
            z5 = PEEK(r + 5)
            z6 = PEEK(r + 6)
            z7 = PEEK(r + 7)
            z8 = PEEK(r + 8)
            DEF SEG = yseg
            POKE x, z0
            POKE x + 1, z1
            POKE x + 2, z2
            POKE x + 3, z3
            POKE x + 4, z4
            POKE x + 5, z5
            POKE x + 6, z6
            POKE x + 7, z7
            POKE x + 8, z8
        CASE 9
            DEF SEG = s
            z0 = PEEK(r)
            z1 = PEEK(r + 1)
            z2 = PEEK(r + 2)
            z3 = PEEK(r + 3)
            z4 = PEEK(r + 4)
            z5 = PEEK(r + 5)
            z6 = PEEK(r + 6)
            z7 = PEEK(r + 7)
            z8 = PEEK(r + 8)
            z9 = PEEK(r + 9)
            DEF SEG = yseg
            POKE x, z0
            POKE x + 1, z1
            POKE x + 2, z2
            POKE x + 3, z3
            POKE x + 4, z4
            POKE x + 5, z5
            POKE x + 6, z6
            POKE x + 7, z7
            POKE x + 8, z8
            POKE x + 9, z9
        CASE 10
            DEF SEG = s
            z0 = PEEK(r)
            z1 = PEEK(r + 1)
            z2 = PEEK(r + 2)
            z3 = PEEK(r + 3)
            z4 = PEEK(r + 4)
            z5 = PEEK(r + 5)
            z6 = PEEK(r + 6)
            z7 = PEEK(r + 7)
            z8 = PEEK(r + 8)
            z9 = PEEK(r + 9)
            z10 = PEEK(r + 10)
            DEF SEG = yseg
            POKE x, z0
            POKE x + 1, z1
            POKE x + 2, z2
            POKE x + 3, z3
            POKE x + 4, z4
            POKE x + 5, z5
            POKE x + 6, z6
            POKE x + 7, z7
            POKE x + 8, z8
            POKE x + 9, z9
            POKE x + 10, z10
        CASE 11
            DEF SEG = s
            z0 = PEEK(r)
            z1 = PEEK(r + 1)
            z2 = PEEK(r + 2)
            z3 = PEEK(r + 3)
            z4 = PEEK(r + 4)
            z5 = PEEK(r + 5)
            z6 = PEEK(r + 6)
            z7 = PEEK(r + 7)
            z8 = PEEK(r + 8)
            z9 = PEEK(r + 9)
            z10 = PEEK(r + 10)
            z11 = PEEK(r + 11)
            DEF SEG = yseg
            POKE x, z0
            POKE x + 1, z1
            POKE x + 2, z2
            POKE x + 3, z3
            POKE x + 4, z4
            POKE x + 5, z5
            POKE x + 6, z6
            POKE x + 7, z7
            POKE x + 8, z8
            POKE x + 9, z9
            POKE x + 10, z10
            POKE x + 11, z11
        CASE 12
            DEF SEG = s
            z0 = PEEK(r)
            z1 = PEEK(r + 1)
            z2 = PEEK(r + 2)
            z3 = PEEK(r + 3)
            z4 = PEEK(r + 4)
            z5 = PEEK(r + 5)
            z6 = PEEK(r + 6)
            z7 = PEEK(r + 7)
            z8 = PEEK(r + 8)
            z9 = PEEK(r + 9)
            z10 = PEEK(r + 10)
            z11 = PEEK(r + 11)
            z12 = PEEK(r + 12)
            DEF SEG = yseg
            POKE x, z0
            POKE x + 1, z1
            POKE x + 2, z2
            POKE x + 3, z3
            POKE x + 4, z4
            POKE x + 5, z5
            POKE x + 6, z6
            POKE x + 7, z7
            POKE x + 8, z8
            POKE x + 9, z9
            POKE x + 10, z10
            POKE x + 11, z11
            POKE x + 12, z12
        CASE 13
            DEF SEG = s
            z0 = PEEK(r)
            z1 = PEEK(r + 1)
            z2 = PEEK(r + 2)
            z3 = PEEK(r + 3)
            z4 = PEEK(r + 4)
            z5 = PEEK(r + 5)
            z6 = PEEK(r + 6)
            z7 = PEEK(r + 7)
            z8 = PEEK(r + 8)
            z9 = PEEK(r + 9)
            z10 = PEEK(r + 10)
            z11 = PEEK(r + 11)
            z12 = PEEK(r + 12)
            z13 = PEEK(r + 13)
            DEF SEG = yseg
            POKE x, z0
            POKE x + 1, z1
            POKE x + 2, z2
            POKE x + 3, z3
            POKE x + 4, z4
            POKE x + 5, z5
            POKE x + 6, z6
            POKE x + 7, z7
            POKE x + 8, z8
            POKE x + 9, z9
            POKE x + 10, z10
            POKE x + 11, z11
            POKE x + 12, z12
            POKE x + 13, z13
        CASE 14
            DEF SEG = s
            z0 = PEEK(r)
            z1 = PEEK(r + 1)
            z2 = PEEK(r + 2)
            z3 = PEEK(r + 3)
            z4 = PEEK(r + 4)
            z5 = PEEK(r + 5)
            z6 = PEEK(r + 6)
            z7 = PEEK(r + 7)
            z8 = PEEK(r + 8)
            z9 = PEEK(r + 9)
            z10 = PEEK(r + 10)
            z11 = PEEK(r + 11)
            z12 = PEEK(r + 12)
            z13 = PEEK(r + 13)
            z14 = PEEK(r + 14)
            DEF SEG = yseg
            POKE x, z0
            POKE x + 1, z1
            POKE x + 2, z2
            POKE x + 3, z3
            POKE x + 4, z4
            POKE x + 5, z5
            POKE x + 6, z6
            POKE x + 7, z7
            POKE x + 8, z8
            POKE x + 9, z9
            POKE x + 10, z10
            POKE x + 11, z11
            POKE x + 12, z12
            POKE x + 13, z13
            POKE x + 14, z14
        CASE 15
            DEF SEG = s
            z0 = PEEK(r)
            z1 = PEEK(r + 1)
            z2 = PEEK(r + 2)
            z3 = PEEK(r + 3)
            z4 = PEEK(r + 4)
            z5 = PEEK(r + 5)
            z6 = PEEK(r + 6)
            z7 = PEEK(r + 7)
            z8 = PEEK(r + 8)
            z9 = PEEK(r + 9)
            z10 = PEEK(r + 10)
            z11 = PEEK(r + 11)
            z12 = PEEK(r + 12)
            z13 = PEEK(r + 13)
            z14 = PEEK(r + 14)
            z15 = PEEK(r + 15)
            DEF SEG = yseg
            POKE x, z0
            POKE x + 1, z1
            POKE x + 2, z2
            POKE x + 3, z3
            POKE x + 4, z4
            POKE x + 5, z5
            POKE x + 6, z6
            POKE x + 7, z7
            POKE x + 8, z8
            POKE x + 9, z9
            POKE x + 10, z10
            POKE x + 11, z11
            POKE x + 12, z12
            POKE x + 13, z13
            POKE x + 14, z14
            POKE x + 15, z15
    END SELECT
    r = r + 16
NEXT dy
END SUB

                               By Toshi Horie
                                      
                                Back 2 Top 
     _________________________________________________________________
                                      
                                  The End!
                                      
   Well folks, this concludes the largest QBoA ever made! This became
   huge in a relatively short period of time, I was quite surprised at
   the number of people who submitted material. Anyways, we'll be back
   with another issue as soon as possible, so be sure to send us your
   letters, articles, reviews, screenshots, comments, questions, news,
   whatever! And watch for the next issue, date unknown!
   
                               Send us Email