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