-=-=-=-=-=-=-=-=-=-=-=-=-=-
                    =   Qbasic                =
                    -        Developers       -
                    =                 Forum   =
                    -  ***** Issue 1 *******  -
                    =  published: 01-21-1999  =
                    -=-=-=-=-=-=-=-=-=-=-=-=-=-


Qbasic Developers Forum is a FREE newsletter made for Advanced Basic
Programming. BASICA/GW-BASIC, Qbasic, and QuickBasic coding methods
are discussed. It is written by Acidus Software. To obtain membership
Email me at: 

mailto:LordAcidus@aol.com

************************************
*The FAT (Feature Allocation Table)*
************************************
(editorials)
-From the Acid Pool...
	Acidus Software ideals and current projects
(features)
-"Ground Control to Major Tom..."
	Modem Communications in Qbasic

-Morphing the Mouse
	How to create and use your own mouse icons

-Player too
	Supporting multi-player games in Qbasic

(every issue)
-Face Lift
	Give speed Compatability to your programs

-Quick Tips
	Fast solutions to little annoying programming problems

-ABORT
	Final Thoughts

-----------------
From the Acidpool
-----------------
	Acidus Software is a small computer company that holds the ideal
that any action that can be done in a another computer language can be done
through BASIC. We are currently designing an OS through Qbasic, as well as
a real time war simulation game called Voices of Liberty(tm). A modem turn
based game similar to Masters of Orion is also being created. We also have
created an FULLY-FUNCTIONABLE BBS through GW-BASIC, Which supports Xmodem 
Zmodem Uploading and Downloading.

--------------------------------
"Ground Control to Major Tom..."
--------------------------------
	THE MODEM. ohhhh, its scary. To most, its a little magic boxs that        
opens our computer to the world. In reality, it is very simple to use. The
modem takes bytes of info, turns it into a noise, and sends it over a phone
line. Theoretically, if you could whisle fast enough and at the right 
pitches, you could send a file with the sounds you make. See, no voodoo magic
stuff. As for sending files, thats easy to. The modem sends a ASCII character
to tell the other computer it is sending a file. It then breaks up that file 
into chunks and sends it in hunks of bytes (128, 1k, it depends). The modem 
then waits for a ASCII character from the other computer telling it that alls
well, and to send the next hunk. 

	Ok, I've had my history lesson now, you say, but how do I do it in
Qbasic? SIMPLE. 4 commands are all you need for simple coommunications.
They are:


OPEN COM.........Open up the modem to get stuff from BASIC
INPUT$...........Gets stuff from the modem
LOC..............Tells you if the modem has any stuff from an outside source
PRINT #..........Send stuff to the modem


	To start work with the modem, you have to open a "path" to it. This        
is just like opening a file, except you use the "OPEN COM" statement. Here
is a sample:


OPEN "COM2:2400,N,8,1,RB2048,TB2048" FOR RANDOM AS #1


	What the #&*! is that?!?, Just like opening a file he says? BULL!
Well, here is a secret, Opened Devices (Your modem) act just like opened
files.

	Don't worry, the only thing you need to woory about is the number 
between "COM" and ":" and the number between ":" and ",N". All the other 
stuff deals with transmition settings and the RB TB things deal with 
Uploading and Downloading. The first Number is COM port number your modem 
is on. Because BASIC was created so long ago, you can only access ports 1 
and 2. If you modem is not on COM port 1 or 2, there is a way around that, 
but it can cause so big time errors with other programs because you manually
switch the memory addresses of the COM ports. Don't worry about that now,
I will go into that in another issue.


	The 2nd number is the Baud. BAUD is the speed of the Modem. Qbasic 
can't access COM ports at any higher speed than 9600, so if you have a 14.4 
Modem, Qbasic can still use it, but it won't go any faster than 9600. Note 
this restriction is for GW-BASIC, BASICA, and QBASIC. I don't know if 
compiled QuickBasic programs have this restriction but I don't think they do.

	To send stuff to your modem, you use the PRINT #n command, where n 
is the file number, in this case 1. But there is no point sending stuff like 
"Hello Chris" to your modem right now, because you are not connected to 
anything. All you have done with the "OPEN COM" statement, is made a little 
path from you modem to your program so they can talk to each other. 

	But you want to talk to an outside sourse, like a friend or a BBS, 
you have to tell the modem to dial a number. To do this you must know that 
ALL modems have a set of commands eched on to their memory chips that make 
them do stuff. You can't just say "Hey modem, dial up 770-555-9806", you have 
to talk in the modem's language. This isn't as bad as it sounds. All commands 
begin with "AT".  Here are some common ones:


MODEM SPEECH             TRANSLATION
-------------------------------------------
"ATDT###-###-####"    | "Hey Modem, dial ###-###-####"
"ATZ"                 | "Hey Modem, This sucks, hang up the phone"
"ATS0=#"              | "Wait until you someone calls and the phone rings  
		      |  # number of times, then try to connect modems"
"ATM2H1L#"            | "Set your speaker Volume at # (1-3)"


	So, if you wanted to call someone first you would use an OPEN COM 
statement to ready the modem then you would use an INPUT statement statement 
to get the phoen number to dial as a string, than use PRINT #n to tlak to the 
modem. Here is an example of a simple phone dialer:
(replace COM# with the COM port your modem is on)


CLS
PRINT "Opening a Path to your Modem..."
OPEN "COM2:2400,N,8,1,RB7048,TB7048" FOR RANDOM AS #1   
PRINT "Please Enter the Number you wish to Call"
INPUT PhoneNumber$
PRINT "Talking to your modem..."
PRINT #1, "ATDT" ;PhoneNumber$
PRINT "There you go, pick up the phone and talk"
PRINT "Press [ESC] to hang up
DO
LOOP UNTIL INKEY$ = CHR$(27)
PRINT #1, "ATZ"


	But here comes the biggest problem of Modem control with Qbasic, HOW 
DO I READ WHAT COMES FROM THE MODEM? Well there is a little Function called 
LOC that does this. The syntax is:


LOC(n)

n is the file number which if you used my sample, would be 1

	LOC tells you where in a file you are. File? I am not accessing a 
file! you exclaim. As I said before, files and devices work the same way. 
But with a modem, LOC tells if it has received anything. Fine, now you know 
if the modem is getting stuff, put how do you know what it is getting? For
that you use the INPUT$(x,y) function.


INPUT$(x ,y)

x is the number of bytes to get from a file/device
y is the number of the opened file/device

	"x" Should ALWAYS be 1. I know this means that only 1 character can
be read on each pass, but this way EVERY character is read, and none are 
skipped. If you were getting an 11 byte transmittion, and "x" was 2, only
the first 10 characters would be read (because it is a multiple of 2) the 
last part would be skipped. This is way for NORMAL communications, keep "x"
as 1. I will going into Downloading in a later newsletter, in which "x" is
not 1. One last thing I will talk about is the "ATS0=#" command. You can        
use this to wait for a call
	
	Alright, I will put this all together give you a fully commented
communications program. You can use this to call up any BBS and interact
with it. Note I have not included any Downloading Abilities. I will Address
this as well as uploading through Qbasic using the XModem and ZModem 
protocols later:


'-------------------------

'Conn-X ver 1.0
CLS
PRINT "Conn-X Ver 1.0           Acidus Software(tm)"
PRINT "What COM port is your Modem on?"
INPUT ">", port$
baud$ = "9600"          '9600 should work with most computers. If you have
			'an older one use "2400"
'Open up that com port
OPEN "COM" + port$ + ":" + baud$+ ",N,8,1,RB2048,TB2048" FOR RANDOM AS #1 
			
PRINT "You can:"
PRINT "1-Call someone"
PRINT "2-Wait for a call"
PRINT "3-Quit"
DO
a = VAL(INKEY$)
LOOP UNTIL a >= 1 and a <= 3    'Get choice
IF a = 3 THEN CLOSE : SYSTEM
IF a = 2 THEN GOTO wait

PRINT "Number to call?"
INPUT ">", number$
PRINT #1, "ATDT" + number       'tell the modem to dail the number
GOTO chat
wait:
PRINT #1, "ATS0=1"              'tell modem to conect after 1 ring

'When a modem connect it returns "CONNECT ####"
'The next hunk of code waits until the modem connects before moving on

a$ = ""
DO
IF LOC(1) THEN a$ = a$ + INPUT$(1, 1)   'if anything in modem add it to a$
LOOP UNTIL INSTR(a$, "CONNECT")         'Wait until modem have Connected

chat:
'If you where waiting for a call, alot of ASCII character will be printed 
'on the screen. Don't worry, that just the computers getting in sync and
'talking
'You also will not see what you type

CLS
PRINT "Conn-X CHAT, press [ESC] to quit
DO
t$ = INKEY$
IF LEN(t$) THEN PRINT #1, t$    'if you typed something send it to the modem
				'this will be send by the modem to the other
				'computer
IF LOC(1) THEN r$ = INPUT$(1, 1)'if the is something to get, get it and save
				'it as r$
IF LEN(r$) THEN PRINT r$;       'if r$ <> "" then print it. the ";" means a
				'line is not started
LOOP UNTIL t$ = CHR$(27)        'keep doing this until [esc] is pressed
PRINT #1, "ATZ"                 'tell the modem to hang up
CLOSE                           'close the open com statment

'-------------------------

       There you go, a simple communications program through Qbasic that
lets you talk to another computer. As I said Uploading/Downloading will be
discussed in a later newsletter

------------------
MORPHING THE MOUSE
------------------
	Qbasic doesn't normal support mouse programming, but through "CALL
ABSOLUTE" the mouse can be accessed. But when you use it, you get an Arrow
looking thing, like in Windows. But in other games,you don't have just one
type of cursor. In "Command & Conquer", You have a wrench cursor to repair 
stuff, a bullseye to attack things, and so on. Even in windows you have 
that hour glass.

	When I began programming "Voices Of Liberty" for Acidus Software,
(Which is a real-time war simulator, similar to "Command & Conquer"), I
wanted to make it look as professional as possible. So I need a way to make
different cursurs other then an arrow. After thinking about it for a very 
long time, I realized that anwser was so simple. I then spent about 6 hours
programming and prefecting, turning my prototype into a series of "SUB"s that
can be used in any program.

	To change the cusor, I had to use "GET" and "PUT" using the mouse's
x and y coordinates. Now, before I go on, you have to know how the mouse 
works in Qbasic. First off, the x and y coordinates are for ONE pixel above
the tip of the arrow. Also, the "CALL ABSOLUTE" that is used to access the 
mouse returns that the screen is always 640x200. This means modifications
are necessary. "Voices of Liberty" uses Screen 1 because I am writting it 
for CGA. Screen 1 is 320x200. when I use CALL ABSOLUTE to get the current
x coordinate, it returns say, 360. To find out where on a 320x200 screen it 
is you must divide that by 2 (640/2=320) This converts the x coordinate into
Screen 1 dimensions. Even in Text mode, you have to to divide the x 
coordinate by 8 to get the column number (640/8=80 columns), and you must 
divide the y coordinate by 8 as well to get the correct row (200/8=25 rows).
Here is a slice of code from Acidus Software's "Voices of Liberty"(tm) which
uses custom made pointers
	

'-------------------------
'POINTER1.BAS
'Prototype ver 3.7 of Voices Of Libertys

'The following are SUB programs that WEREN'T written by Acidus Software
'They simply load the mouse and check it x/y coordinates

DECLARE SUB MouseDriver (ax%, bx%, cx%, dx%)
DECLARE FUNCTION Initialize% ()
DECLARE SUB CursorOff ()
DECLARE SUB cursoron ()
DECLARE SUB GetMouse (lb%, rb%, xMouse%, yMouse%)
DECLARE SUB LocateCursor (x%, y%)



'The following are SUB used to make your own cursor
DECLARE SUB LoadPointer (load$)
DECLARE SUB MovePointer (xM%, yM%)

DIM SHARED PointerX
DIM SHARED PointerY
DIM SHARED DimX         'how many pixels wide the cusor is 
DIM SHARED DimY         'how many pixels tall the cusur is
DIM SHARED pointer(100)         'The cursors image
DIM SHARED UnderPointer(100)    'image of what is under the cursor


'The following allows for mouse use in Qbasic. It is NOT written by Acidus
'Software
DIM SHARED Mouse$
Mouse$ = SPACE$(57)
FOR i% = 1 TO 57
  READ a$
  H$ = CHR$(VAL("&H" + a$))
  MID$(Mouse$, i%, 1) = H$
NEXT i%
DATA 55,89,E5,8B,5E,0C,8B,07,50,8B,5E,0A,8B,07,50,8B
DATA 5E,08,8B,0F,8B,5E,06,8B,17,5B,58,1E,07,CD,33,53
DATA 8B,5E,0C,89,07,58,8B,5E,0A,89,07,8B,5E,08,89,0F
DATA 8B,5E,06,89,17,5D,CA,08,00        
CLS
ms% = Initialize%
IF NOT ms% THEN
PRINT "Mouse not found"
END
END IF

'GOTO bypass            'UN comment this line after you run the program once
'the following lines of code make a cursor
'I make all my mointers 10x10

SCREEN 1
CLS
FOR y = 1 TO 10
FOR x = 1 TO 10
READ r
PSET (x, y), r
NEXT
NEXT
GET (1, 1)-(10, 10), pointer

DEF SEG = VARSEG(pointer(0))
BSAVE "cursor1.cpf", 0, 100

DATA 3,0,0,0,0,0,0,0,0,3
DATA 0,3,0,0,0,0,0,0,3,0
DATA 0,0,3,0,0,0,0,3,0,0
DATA 0,0,0,3,0,0,3,0,0,0
DATA 0,0,0,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,0,0,0
DATA 0,0,0,3,0,0,3,0,0,0
DATA 0,0,3,0,0,0,0,3,0,0
DATA 0,3,0,0,0,0,0,0,3,0
DATA 3,0,0,0,0,0,0,0,0,3


ByPass:
SCREEN 1
'This creates a random background for you to move your cursor over:

CLS
RANDOMIZE TIMER
FOR a = 1 TO 100
xx = INT(RND * 300) + 1
yy = INT(RND * 180) + 1
cc = INT(RND * 2) + 1
LINE (xx, yy)-(xx + 20, yy + 20), cc, BF
NEXT
'To call a custom cusur (which I call pointers) you must first load
'it. Be sure to put the correct wide and tall Dim's, because your cursor is
'centered on the tip of the default arrow head.
'You must also always turn off the cursor before loading a custom pointer

DimX = 10               '10 pixels wide
DimY = 10               '10 pixels tall
LoadPointer "Cursor1.cpf"


pointerloop:
DO
x = xMouse%
y = yMouse%
CALL GetMouse(lb%, rb%, xMouse%, yMouse%)
IF x <> xMouse% OR y <> yMouse% THEN MovePointer xMouse%, yMouse%
LOOP UNTIL INKEY$=CHR$(27)
STOP

SUB CursorOff
 'Turns off the mouse cursor
 ax% = 2
 MouseDriver ax%, 0, 0, 0
END SUB

SUB cursoron
  'Turn on the mouse cursor
  ax% = 1
  MouseDriver ax%, 0, 0, 0
END SUB

SUB GetMouse (lb%, rb%, xMouse%, yMouse%)
  ax% = 3
  MouseDriver ax%, bx%, cx%, dx%
  lb% = ((bx% AND 1) <> 0)
  rb% = ((bx% AND 2) <> 0)
  xMouse% = cx%
  yMouse% = dx%
END SUB

FUNCTION Initialize%
  ax% = 0
  MouseDriver ax%, 0, 0, 0
  Initialize% = ax%
END FUNCTION


SUB LoadPointer (load$)
'Load the image of your custom pointer
DEF SEG = VARSEG(pointer(0))
BLOAD load$, 0
DEF SEG

'Find out the current x,y coordinates of the mouse
CALL GetMouse(lb%, rb%, xMouse%, yMouse%)

'The next statements make it so the center of your pointer is the x,y 
'coordinates of the mouse by dividing the width and heigth by 2
'the xMouse%/2 is used to get the x coordinate into Screen 1 dimensons
'PointerX and PointerY are the top left coordinates of the pointers image.
'They are the top left cornor becuase that is where the image must be PUT
'so that the center of the pointer is the returned x,y Mouse coordinates

PointerX = (xMouse% / 2) - INT(DimX / 2)
PointerY = yMouse% - INT(DimY / 2)

LOCATE 1: PRINT PointerX, PointerY      

'The foloowing make sure you stay inside the bounds of the screen
'in screen mode 1, the dimensions are 320x200, so change the following
'numbers if you have different dimensions (like 640x200)

IF PointerX < 1 THEN PointerX = 1 
IF PointerX > 319 - (DimX) THEN PointerX = 319 - (DimX)
IF PointerY < 1 THEN PointerY = 1
IF PointerY > 199 - DimY THEN PointerY = 199 - DimY

'The next statement saves the image of what will be under your pointer

GET (PointerX, PointerY)-(PointerX + DimX, PointerY + DimY), UnderPointer
'The next statement places your pointer at that location

PUT (PointerX, PointerY), pointer, OR

END SUB

SUB LocateCursor (x%, y%)
  'This moves your ax% = 4
  cx% = x%
  dx% = y%
  MouseDriver ax%, 0, cx%, dx%
END SUB

SUB MouseDriver (ax%, bx%, cx%, dx%)
  DEF SEG = VARSEG(Mouse$)
  Mouse% = SADD(Mouse$)
  CALL Absolute(ax%, bx%, cx%, dx%, Mouse%)
END SUB

SUB MovePointer (xM%, yM%)
'This sub is called when the mouse is moved to a new postion

'1st replace the background
PUT (PointerX, PointerY), UnderPointer, PSET

'calculate the new location of the top right cornor of your pointer
'the xM%/2 is to get the right Dimensions for screen 1

PointerX = (xM% / 2) - INT(DimX / 2)
PointerY = yM% - INT(DimY / 2)

'Make sure PointerX and PointerY are within Screen Dimensions

IF PointerX < 1 THEN PointerX = 1
IF PointerX > 319 - (DimX) THEN PointerX = 319 - (DimX)
IF PointerY < 1 THEN PointerY = 1
IF PointerY > 199 - DimY THEN PointerY = 199 - DimY

'Save the image under the pointer
GET (PointerX, PointerY)-(PointerX + DimX, PointerY + DimY), UnderPointer

'place the pointer

PUT (PointerX, PointerY), pointer, OR
END SUB

'-------------------------

	There you go. This method is very useful, and with a little tinkering
you could make it support many different custom cursors.

----------
PLAYER TOO
----------

	Games. They pass the time. But think video games. What kind are 
a lot of fun? The kind where you play with/against another human player.
Human players add an element of suprise to each game. They learn from
they past mistakes, and adopt new styles. Most Computers have a RANDOM
type feature in them somewhere, no matter how complex the Artifical
Intellence is. So, to build mutli-player, and thus, more enjoy programs,
Game coders MUST learn how to program for to players.

	There are only 2 ways to have multi-player games in Qbasic, as on any        
computer. One way is to play over a Modem/Network. The other way is to have
both characters play on the same computer.
	
	Many people overlook how hard it is to support 2 players evenly
in Qbasic. A method I always see is both players use the same keyboard. This
method looks good, but doesn't work at all. Look at this example from a never
released Acidus Software game "FIGHTER's DANCE":


StartOfGameLoop:
...blah...        
a$ = UCASE$(INKEY$)
if a$ = "4" THEN 'move player 1 left
if a$ = "6" THEN 'move player 1 right
if a$ = "0" THEN 'player 1 punches

if a$ = "A" THEN 'move player 2 left
if a$ = "D" THEN 'move player 2 right
if a$ = "\" THEN 'player 2 punches
...blah...        
...blah...        
GOTO StartOfGameLoop

	
	There are BIG TIME flaws to this method. First, only one player can 
move only once with ever GameLoop pass. Second, if say, Player 1, holds down 
[6], then his character will move and Player 2 doesn't get the chance to do 
anything.

	The ONLY way to have 2 players play the keyboard is to use a lot of 
"ON KEY(n) GOSUB label" statements. Another way to have 2 players play on 
the same computer is if you have  2 joysticks. Use the STICK(n) and STRIG(n) 
functions. The only way to Avoid the problem of one player hogging the input
such as in "FIGHTERS DANCE", you have to use these 2 methods.

	A final way to have multi-player games is to use a Modem/Network.
Now, Networks are hard as #%&* to deal with. Since I don't have one at home
I can fool around with, I will not go into any form of Network programming
right now. Modems, however, I know quite a bit about. If you don't, read the
article entitled "Ground Control to Major Tom..." in this issue.

	There are really 2 forms of Multi-player games using a Modem.

1-Real time
	This means the same program is running on 2 different machines. Both 
players go at the same time, and the Computer constatly talk to each other 
updating each players status. This is how almost all the newer games are.
"Warcraft", "Command & Conquer", "Doom", and "Quake" are all examples of 
Realtime modem games.

	Realtime modem games are fun to play, because you must react 
instantly to the other players moves. Real time also makes your game run
slower, because it must often (Normal once through each game loop), send and
receive game infomation. In complex games, transporting large strings of info
becomes a problem. I talk later on how to compress data, but I am currently
working on saving the game data as a binary file and sending the file across
the modem. I will go more into sending game data in file for in a later issue.

2-Turn based
	This means a player does all his moves, then another player does all        
his moves.
	
	This is method is a older way of multi-player programming, but is 
still quite good in the right situations. It is also faster because the modem
doesn't have to transmit ever second. It is only suited for some games because
you don't see what your opponent did until your next turn. There are 2 ways to 
do this method.

2a-Turn based dual action
	In this Both player are playing their game at once at there on 
seperate machines. The players do their stuff then select the end of their 
turn. The computers then transmit all the new data. The next turn begins with
both players see what the other did last turn, and react. If one player ends
thier turn before another player, they must wait until the other is done
before the new data arrives.

2b-Turn based single action
	Each player moves one at a time, and then end their turn. At the end 
of the turn, The computers transmit new data, and the next person can go. This
was the first kind of multi-player games, and are very slow because you have 
to wait until the other person is done before you can move. This method
is good for games like chess, and other board-game type games. Simple war 
games are also programmed using this method.

	To transmit game infomation over a modem, you must have a way to
tell where a number ends, and where it begins. Else "8210" could be a 8 and
210, 82 ans 10, or 821 and 0. I don`t recogmend sending strings of actual
text across a modem, because of the extra time it takes. Now for an
example. Lets say I am playing a racing game and I need to tell send only
my current place, speed, and distance traveled to the other computer. I would
use my system of make all these number 3 digits, so that way since all the
numbers are 3 digits long, the other computer can extract them corrected.
lets say I'm in 3rd place, going 127mph, and I've gone 41 miles so far. 
I would make 3 be 003, the speed can stay as is because it is already 3 
digits, and distance would become "041"
	This FUNCTION returns a string representation of any number pumped 
into it as a 3 digit string.


FUNCTION MakeString$(x)
if x>=1000 then 
print "Number more than 3 digits"
MakeString$=""
exit function
end if
if x>=100 then  '3 digit
MakeString$=mid$(str$(x),2,3)   'the mid$ function is used becuase when ever
				'you convert a number to a string, a space is
				'automaticly added to the begining by BASIC
				'The mid$ is used to bypass it so your string
				'contains only numbers
exit function
end if
if x>=10 then   '2 digits
MakeString$="0"+mid$(str$(x),2,2)
exit function
end if
'Must be 1 digit
MakeString$="00"+mid$(str$(x),2,1)
end function

	I then would piece these 3 integers into a single string of numbers to 
transmit. I would use a code sidbit thing this:


SendMe$=MakeString$(place)+MakeString$(speed)+MakeString$(distance)

	
	Using the numbrs I gave before, you would send a string that looked 
like this:

"003127041"

	
	You than send it over the modem using PRINT #n,SendMe$. The receiveing
computer gets the values you sent by a code hunk similar to the following.

receive$=""

Do
if loc(1) then receive$=input$(loc(1),1)
loop until len(receive$)=9              'wait until all numbers are received
'Extract the vals from ,the recieved string

OtherPlayersPlace=val(mid$(receive$,1,3))
OtherPlayersSpeed=val(mid$(receive$,4,3))
OtherPlayersDistance=val(mid$(receive$,7,3))

	There you go, a simple way to transmit game infomation over the 
modem thus created multi-player games.

----------
Face Lift
----------
	Don't you hate it when you are playing some game for Basic and 
you get a "Enter Speed (1-9000)"-type message. It is SO unprofessonal. It
means some where in the program (proably at the end of the main loop) is
a little bit of code such as:

FOR delay = 1 to NumberTheyEnteredForSpeed
NEXT

	This is so the program won't go to fast on some computers. Thats all 
well and good, but it is pointless to ask the user when you can do it 
yourself. It is like asking the user to seed the RANDOMIZE statement. But, 
if you don't ask, then how do you know how long to delay at the end of the 
main game loop you may wonder. Well that is easy too, heres what you do:

1-edit you code to this:

	...
	Opening crap like "DECLARE"s and "ON...GOTO"s
	...
	TIMER ON                                        'add this

	MainGameLoop:
	start = TIMER                                   'add this
	...
	Your game logic stuff
	...
	FOR delay = 1 to NumberTheyEnteredForSpeed      'The delay loop
	NEXT
	LOCATE 1 : PRINT TIMER - start                  'add this
	GOTO MainGameLoop


2-Run the program many times, and enter a new number for speed each time 
  until you get a speed that is not to fast and not to slow for the game.
  Once you get it, look at top right cornor of the screen and write down
  the number that keeps appearing there.
  (For the example's sake, we are going to say it was .34)

3-Re-edit your code to look like this
	...
	Opening crap like "DECLARE"s and "ON...GOTO"s
	...
	TIMER ON

	MainGameLoop:
	start = TIMER
	...
	Your game logic stuff
	...
	DO : LOOP UNTIL TIMER - start > .34
	GOTO MainGameLoop

	Of course, your number proably won't be .34, so replace it with 
your number The DO : LOOP waits for .34 seconds from the start of the 
MainGameLoop until it makes another pass. 

4-How does this work?
Here is an Example:

Bob is playing PACMAN(tm) on an INTEL Pentium II  300mhz

	It takes the Pentium .09 seconds to go throught the whole game loop. 
The program then sits in the DO : LOOP thingy for .25 seconds (.34 - .09=.25)
The program then goes back to the start of the Main Game loop and repeats.
 
Bill is Playing PACMAN(tm) on a 386sx 33mhz

	It takes the 386sx .20 seconds to go throught the whole game loop. 
The program then sits in the DO : LOOP thingy for .14 seconds (.34 - .20=.14)
The program then goes back to the start of the Main Game loop and repeats.

No matter what Computer is used, the Main Game Loop is only run once every
.34 seconds. What happens if you have a really slow computer?

Dave is poor and has to run a copy of PACMAN(tm) that he stole on a 
IBM XT (c. 1984)

	It takes the piece-of-s...er...XT .8 seconds to go through the main 
game loop Then program hits the DO : LOOP thingy and says "Oh, .8 seconds 
have passed, so I don't have to wait at all in the DO : LOOP thingy, because 
it took me longer than .34 seconds because I suck. I'll just exit the DO : 
LOOP thingy and go back to the start of the main game loop!"

	This makes the program look better, and run the same on all computers.
Now, I know you will NEVER come across an old XT, 386s are all but dead, 
and 486s are slowly dying; but this is still helpful because a Pentium 75mhz 
is much slower then a Pentium MMX 166mhz which is slower than a Pentium II 
333Mhz.

----------
Quick Tips
----------

How do I turn off the Keyboard?

This is a wicked trick to do to someone; can be used as a prack
by Compiling this to an EXE and adding it to a AUTOEXEC.BAT; and
makes a great addition to a Security Program if the wrong Password
is entered.

To disable all input from the Keyboard:
DEF SEG = 64
OUT 97, 204
To Re-able the Keyboard:
DEF SEG = 64
OUT 97, 76
******BE CAREFUL********
You can EASILY lock yourself out and have to Reboot to use your keyboard
again

How Do I Reboot a Computer?

There are many way to do this, But I know of 3 that ALWAYS work, and have
been tested on XT's, 386's, 486's, and Pentiums. Here you go:

For a COLD BOOT:

SHELL "ECHO G = FFFF:0000 | DEBUG"      'This only works if DEBUG.EXE is in a
					'pathed directory
	-or-
The Shell one is slower than the next method. It also leave 2 files behind
with gibberish names that Debug makes.


DEF SEG = &HFFFF                        'This is the better one
CALL Absolute(0)

For a WARM BOOT:

DEF SEG = 0
POKE &H473, &H12        'FLAG FOR WARM BOOT
POKE &H472, &H34        'FLAG FOR WARM BOOT
DEF SEG = &HFFFF
CALL Absolute(0)

How do I Center Text?

This is another SUB I use all the time that gives your programs a very
professional look. There are 2 versions of this.
Cen40 is mainly used in SCREEN mode 1, 7, and 13, but it just depends on the
WIDTH setting. Use Cen on 80 WIDTH

'SUB Cen(txt$, row)
LOCATE row, 39 - LEN(txt$) / 2: PRINT txt$
END SUB

'SUB Cen40(txt$, row)
LOCATE row, 19 - LEN(txt$) / 2: PRINT txt$
END SUB


-----
ABORT
-----
	Well, thats the first issue of Qbasic Developers Forum. I hope I 
was able to help you expand your ability to program, and to create better 
programs. If you like what you learned, let me know. My Email address is

LordAcidus@aol.com
or snail mail

Billy Hoffman 
c/o Acidus Software
1349 Garrick Way
Marietta Ga, 30068

Oh, I have a BBS that runs from 12am til 12pm EST, open to the public 
Sept 1, 1998

Hack the planet,
Acidus

----------------------------
This free issue has been contributed to Toshi's Project Page 
by the editor Lord Acidus.  This issue may be downloaded from 
http://www.ocf.berkeley.edu/~horie/project.html.