Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
BOWLING for John
#31
Nice work, Meg!

I still had a problem, not having the high scores file, so I did this:

Code:
OPEN "BOWLING.HSR" FOR BINARY AS #1
     MyLOF = LOF(1)
     CLOSE
     IF MyLOF > 0 THEN
          OPEN "BOWLING.HSR" FOR INPUT AS #1           'OPEN HIGHSCORE FILE
              INPUT #1, HighScore.Points%                  'GET SCORE FROM FILE
              LINE INPUT #1, HighScore.Name$               'GET NAME FROM FILE
          CLOSE #1                                     'CLOSE HIGHSCORE FILE
     ELSE
          HighScore.Points% = 0
          HighScore.Name$ = "(None)"
          OPEN "BOWLING.HSR" FOR OUTPUT AS #1          '..OPEN HISCORE FILE
               PRINT #1, Score%                        '..SAVE SCORE TO FILE
               PRINT #1, YourName$                     '..SAVE NAME TO FILE
          CLOSE #1                                     '..CLOSE HISCORE FILE
     END IF
     PRINT "HI-SCORE: ";
     PRINT HighScore.Points%; "BY "; HighScore.Name$   'SHOW THE HIGH SCORE

That would be in the initialization. The other read, testing for high score, can just be a simple OPEN.

Mac

P.S. Novel convention, indenting with OPEN. Many programs have the OPEN and CLOSE far removed, so most never think of it as something like DO LOOP requiring indentation of intervening commands.
Reply
#32
Good adjustment. Yeah, I'm pretty crazy about indentation and comments and whatnot (as you can prolly tell from my code sampes all over this forum).

When I write code, I *always* end the loop/whatever as soon as I write the first line:

Code:
FOR i% = 1 TO 10
NEXT i%

OPEN "file.dat" FOR INPUT AS #1
CLOSE #1

WHILE INKEY$ = ""
WEND

Then, I put a space between 'em and start writing the guts, indented. It drives me crazy if I ever write the top line without the bottom one immediately following. >.>

*peace*

Meg.
Reply
#33
It seems like some of you don't care for "GOTO" statments/commands.
It would be safe then to say that you wouldn't like to use the:
JP 120, JE 130, and JNE 140 commands in asm then, right?
(The 120,130,140 are all arbitrary numbers of course.)
As these equate with: JP 120 = GOTO 120 , JE 130 = IF A = A THEN GOTO 130, and JNE 140 = IF A<>B THEN GOTO 140 statments.
The "block" statments make it easier to read/follow (for some), but the GOTO statments can actually min. the size of the program as well as the speed of the program.
Like it or not, in the BLOCK formation each and every line of code is still evaluated(sp?) until the THEN is reached. Even if the first line makes it true. The rest is then compared against the flag, that has already been set if the true statment has been reached to see if it was set. :o
Me thinks we all have our own preferences; and with that in mind, I feel it's safe to say that one way is neither better nor worse than the other. :wink:
(O.K. kids...Have at it!)
adsherm
Reply
#34
I indent OPEN...CLOSE sections as well. It makes sense to me to do it...after all, you've got something started (kind of like a DO...LOOP or a FOR...NEXT), so might as well indent all the stuff that happens within that "thing" so you know what goes on between the time it's opened and the time it's closed.

dadsherm: it's been said a million times that in assembly, jumping is your only option; aka you HAVE to use "GOTO". In QB, you don't have to use it...it's not required and if overused, can make debugging a nightmare. The whole reason DO...LOOP and other such code blocks were invented was to make a coder's life easier and make code easier to read. Using GOTOs still has its purposes, but like any tool, can be dangerous in unskilled hands. It's very useful for escaping redundant loops but very bad for major program flow operations.
I'd knock on wood, but my desk is particle board.
Reply
#35
My issue with this program are not that GOTOs are used; it is *how* they are used. The logical flow of the original posted code was terribly unefficient. It looped via GOTO when no loop was needed, running over the same code multiple times when it only needed to be processed once.

Sure, discounting the problem of computer speed--which I attempted to adjust for via my updated code--it is just a matter of opinion. *My* opinion is that code is much easier to plan, follow, and debug if your loops and program jumps make logical sense according to your variables:

If you are bowling and need 10 frames: make a variable Frame% and a FOR/NEXT loop from 1 to 10.

If you are moving a ball left and right while waiting for a keypress: have variables hold the ball's coordinates and the ball's direction, instead of two blocks of code, one which moves right, and one that moves left, with conditional goto statements redirecting program flow after running.

Basically, I like to be able to see where the program is going when the loop STARTS, instead of finding the GOTO and figuring out where it jumps to AFTER the "guts" of the loop have been executed the first time.

Yes, I'll admit it is just opinion in the end. In the meanwhile, I will continue to preach easy-to-follow coding practices to beginner-ish programers, because I believe that it will enable them to advance further by not having to go crazy figuring out why their program doesn't run properly when they do inevitably make a mistake, as we all do. :)

*peace*

Meg.
Reply
#36
Meg and adosorken,

I agree with both of you, well with the exception of the " have to use them" in asm; However to not use them really restricts the size of the program. :roll:
A person can use GOTO's to the extenct that it makes a plate of spagetti look like a straight line. :o
(I remember that's how some of mine were in the beggining days of programming :oopsSmile
I guess what I was refering to, are those that look at GOTO commands as an unnecessary evil.
Oh well. I just thought I'd share that with those that read this thread. :wink:
adsherm
Reply
#37
Again... I think I'll set the original post in favourites and link to it everytime.

GOTO is useful in several scenarios.

It should be avoided if you are a bad coder or a newbie, but once you know what you are doing, a "GOTO" in time will save your guts, and won't turn your code into spaghetti.

Of course it 'can' be avoided, but you can get faster code using it in some places.

For example, exit a 27 nested loops structure. Without GOTO: you have to go through 27 comparisons. With GOTO: you just jump out.

Don't say "GOTO is bad" just 'cause you listened it somewhere. Specially when you haven't thought in all its applications.
SCUMM (the band) on Myspace!
ComputerEmuzone Games Studio
underBASIC, homegrown musicians
[img]http://www.ojodepez-fanzine.net/almacen/yoghourtslover.png[/i
Reply
#38
I further modified the program to allow the user to speed up or slow down the ball movements, etc.

Whenever anything is happening, you can hold down ALT to speed it up or hold down CTRL to slow it down.

This is kept in the high scores file so next time you play, you have the same speed.

Mac

Code:
DECLARE SUB Speed (c%)
'THIS PROGRAM IS A SUBMISSION TO QBASICNEWS FORUM WRITTEN BY JOHN KREITLOW.
'IT HAS BEEN REORGANIZED TO REMOVE GOTOs, UNNEEDED LOOPS, AND GENERALLY MADE
'QUITE A BIT EASIER TO FOLLOW, LOGICALLY.  PLEASE LET ME KNOW IF THERE ARE
'ANY CHANGES I MADE WHICH ARE TOO DIFFICULT TO UNDERSTAND.  THANKS!
'
'                                                            - 01/27/2005 MB.
'Also changed by Mac to remove excess file IO (Only read once and only write
'if there are changes).
'Also changed by Mac to allow the user to change speed of operations
'  increase (Hold down ALT key)
'  decrease (Hold Down CTRL key)
'These changes are recorded for subsequent runs


'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'Subroutine and Function declarations.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
DECLARE SUB Initialize ()               'SET UP INITIAL PROGRAM STATE
DECLARE SUB Intro ()                    'DISPLAY INTRO SCREEN
DECLARE SUB Instructions ()             'DISPLAY GAME DIRECTIONS
DECLARE SUB ResetPins ()                'MAKE ALL PINS STANDING
DECLARE SUB DrawLane ()                 'DRAW THE LANE, PINS, AND INFO
DECLARE SUB RollBall ()                 'ROLL THE BALL, AND CHECK COLLISIONS
DECLARE SUB HitPin (n%)                 'RECURSIVE PIN-COLLISION ROUTINE
DECLARE SUB StrikeOrSpare ()            'FLASH A MESSAGE FOR STRIKE OR SPARE
DECLARE SUB GameOver ()                 'END THE CURRENT GAME
DECLARE SUB CheckHighScore ()           'SEE IF USER SET A NEW HIGH SCORE
DECLARE FUNCTION GetBallColor% ()       'CHOOSE BALL COLOR
DECLARE FUNCTION GetLane% ()            'CHOOSE LANE TO RELEASE BALL DOWN
DECLARE FUNCTION GetPower% ()           'CHOOSE POWER OF BALL ***NOT USED***

    
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'The following variables can be used / changed in any subroutine or function
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
COMMON SHARED adjScore%                 '# OF POINTS SCORED IN CURRENT ROLL
COMMON SHARED Score%                    'TOTAL SCORE FOR THE GAME
COMMON SHARED Frame%                    'WHICH FRAME IT IS [1 THROUGH 10]
COMMON SHARED Roll%                     'WHICH ROLL IT IS [1 THROUGH 2]
COMMON SHARED QuitFlag%                 '0=CONTINUE GAME, 1=END GAME
COMMON SHARED OneSecond&                '# OF LOOPS COMPUTER RUNS / SECOND

'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'Get High Score and Speed Settings from file (or defaults if no file)
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
TYPE HSS
     UserHigh   AS INTEGER                'High Score
     UserName AS STRING * 20              'Name of Player
     S1     AS INTEGER                    '{
     S2     AS INTEGER                    '{ See SPEED commands
     S3     AS INTEGER                    '{ for usage of this
     S4     AS INTEGER                    '{ speed
     S5     AS INTEGER                    '{
END TYPE
DIM SHARED HSS AS HSS
OPEN "BOWLING.HSS" FOR BINARY AS #1: MyLOF = LOF(1): CLOSE
IF MyLOF = LEN(HSS) THEN                  'Correct LengthOfFile (LOF)
  OPEN "BOWLING.HSS" FOR RANDOM AS #1 LEN = LEN(HSS)
  GET #1, 1, HSS
  CLOSE
ELSE
  HSS.UserHigh = 0
  HSS.UserName = "(None)"
  HSS.S1 = 5
  HSS.S2 = 50
  HSS.S3 = 8
  HSS.S4 = 80
  HSS.S5 = 7
END IF

' Make a copy to see if user made any changes during game
DIM SHARED HSSOrig AS HSS
HSSOrig = HSS

'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'Variable TYPE declarations.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
TYPE BallType
     x    AS INTEGER                    'X-COORDINATE OF BALL
     y    AS INTEGER                    'Y-COORDINATE OF BALL
     c    AS INTEGER                    'COLOR OF BALL
     p    AS INTEGER                    'POWER OF BALL ***NOT USED***
END TYPE
DIM SHARED Ball AS BallType             'CREATE A BALL

TYPE PinType
     x    AS INTEGER                    'X-COORDINATE OF PIN
     y    AS INTEGER                    'Y-COORDINATE OF PIN
     Up   AS INTEGER                    'IS THE PIN STANDING? 1=YES 0=NO
END TYPE
DIM SHARED Pin(1 TO 10) AS PinType      'CREATE ARRAY OF 10 PINS

'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'These next few lines set up the game to be played.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
CALL Initialize                         'INITIALIZE SOME GAME VARIABLES
CALL Intro                              'SHOW THE INTRO SCREEN
Ball.c = GetBallColor%                  'GET DESIRED BALL COLOR FROM USER
CALL Instructions                       'DISPLAY GAME INSTRUCTIONS

'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'Here is the main game loop.  This runs through 10 frames, 2 rolls per frame
'unless the user hits the escape key.  If a strike is bowled, the 2nd roll
'gets skipped for that frame.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
DO WHILE QuitFlag% = 0                  '---MAIN GAME LOOP UNTIL QuitFlag%---
     Score% = 0                         'SET TOTAL GAME SCORE TO ZERO
     FOR Frame% = 1 TO 10               '   ----THIS LOOPS EACH NEW FRAME----
          CALL ResetPins                '   SET ALL THE PINS TO STANDING
          FOR Roll% = 1 TO 2            '      ---THIS LOOPS EACH NEW ROLL---
               CALL DrawLane            '      DRAW THE LANE, PINS, & INFO
               Ball.x = GetLane%        '      USER SELECTS LANE TO BOWL DOWN
               IF QuitFlag% = 1 THEN    '      DID THEY HIT ESCAPE?
                    Roll% = 2           '      ..YES. THEY CANCELLED BOWL.
                    Frame% = 10         '      ....SKIP ALL REMAINING FRAMES.
               ELSE                     '      ..NO. THEY ACTUALLY BOWLED.
                    Ball.p = GetPower%  '      ....***POWER DOES NOTHING***
                    CALL RollBall       '      ....ROLL THE BALL DOWN LANE.
               END IF                   '
          NEXT Roll%                    '      -----END OF THE ROLL LOOP-----
     NEXT Frame%                        '   ------END OF THE FRAME LOOP------
     CALL GameOver                      '   END THE CURRENT BOWLING GAME
LOOP                                    '----END LOOP WHEN QuitFlag% IS 1----

'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'End the program, return control to the O/S after writing HSS file
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Diffs = 0                               ' To see if there are any differences  
IF HSS.UserHigh <> HSSOrig.UserHigh THEN Diffs = -1
IF HSS.UserName <> HSSOrig.UserName THEN Diffs = -1
IF HSS.S1 <> HSSOrig.S1 THEN Diffs = -1
IF HSS.S2 <> HSSOrig.S2 THEN Diffs = -1
IF HSS.S3 <> HSSOrig.S3 THEN Diffs = -1 ' -1 is BOOLEAN TRUE (0 is FALSE)
IF HSS.S4 <> HSSOrig.S4 THEN Diffs = -1
IF HSS.S5 <> HSSOrig.S5 THEN Diffs = -1
IF Diffs THEN
    OPEN "BOWLING.HSS" FOR RANDOM AS #1 LEN = LEN(HSS)
    PUT #1, 1, HSS
    CLOSE
END IF
SYSTEM

'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'This data contains the x- and y-coordinates of the 10 pins.  The Initialize
'subroutine loads this data into the 10-element array, Pin().
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
DATA 70  , 10
DATA 110 , 10
DATA 150 , 10
DATA 190 , 10
DATA 90  , 30
DATA 130 , 30
DATA 170 , 30
DATA 110 , 50
DATA 150 , 50
DATA 130 , 70

SUB CheckHighScore
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     'Check to see whether the user has beaten the high score.
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

     IF Score% > HSS.UserHigh THEN                'HIGH SCORE BEATEN!!

          PRINT "CONGRATULATIONS! YOU BEAT THE HIGH"   '..\
          PRINT "SCORE. YOU SHOULD BE IN THE HALL"     '.. > DISPLAY MESSAGE
          PRINT "OF FAME!"                             '../
          PRINT
          PRINT "OLD HISCORE: "; HSS.UserHigh     '..\ SHOW OLD BEST
          PRINT "MADE BY: "; HSS.UserName           '../ SCORE AND NAME
          PRINT
          PRINT "YOUR SCORE:"; Score%                  '..SHOW YOUR SCORE

          INPUT "PLEASE ENTER YOUR NAME: ", HSS.UserName  '..GET USER NAME
          HSS.UserHigh = Score%                          '..SAVE SCORE
     ELSE                                              'HIGH SCORE NOT BEATEN
          PRINT "TOTAL SCORE:"                         '..\
          PRINT Score%                                 '../ SHOW USER SCORE
     END IF
END SUB

SUB DrawLane
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     'Draw the bowling lane.  This will happen at the start of each roll.
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     SCREEN 7                                          '\ SET AND CLEAR
     CLS                                               '/ THE SCREEN
    
     FOR i% = 1 TO 10                                  '-START LOOP 1 TO 10--
          IF Pin(i%).Up THEN                           'IS THIS PIN STANDING?
               CIRCLE (Pin(i%).x, Pin(i%).y), 5, 15    ' ..YES, SO DRAW IT.
          END IF
     NEXT i%                                           '---END LOOP AT 10----

     LINE (300, 10)-(310, 190), 4, BF                  'DRAW RED BOX ON RIGHT
     LINE (30, 10)-(30, 190), 15                       'DRAW WHITE LINE LEFT
     LINE (230, 10)-(230, 190), 15                     'DRAW WHITE LINE RIGHT

     COLOR 15                                          'SET COLOR: WHITE
     LOCATE 2, 30: PRINT "SCORE:"                      '\
     LOCATE 3, 30: PRINT Score%                        ' \
     LOCATE 5, 30: PRINT "FRAME:"                      '  \ SHOW THE SCORE,
     LOCATE 6, 30: PRINT Frame%                        '  / FRAME, AND ROLL
     LOCATE 8, 30: PRINT "ROLL:"                       ' /
     LOCATE 9, 30: PRINT Roll%                         '/
END SUB

SUB GameOver
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     'Either the user bowled the last frame, or hit escape during play.
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     SCREEN 0                                          '\
     WIDTH 80, 25                                      ' > SET & CLEAR SCREEN
     CLS                                               '/

     CALL CheckHighScore                               'CHECK FOR NEW HISCORE

     PRINT
     PRINT "CREATED BY JOHN KREITLOW"                  '\ CLOSING GAME
     PRINT "IN ASSOCIATION WITH RADIUM-V"              '/ CREDITS
     PRINT
    
     PRINT "Play Again? (Y/N)"                         'WANT TO PLAY AGAIN?
     DO                                                '-----START LOOP------
          k$ = UCASE$(INKEY$)                          'MONITOR KEYPRESS
     LOOP UNTIL k$ = "Y" OR k$ = "N"                   '---END WHEN Y OR N---
     IF k$ = "N" THEN QuitFlag% = 1 ELSE QuitFlag% = 0 'SET QuitFlag%
END SUB

FUNCTION GetBallColor%
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     'Change to Screen Mode 7 to display the balls and clear keyboard buffer.
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     WHILE INKEY$ <> "": WEND
     SCREEN 7

     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     'Make a string to hold the seven ball color values.
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     BallColors$ = "01020304051214"
    
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     'Display all seven balls, and a message prompting selection.
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     FOR i% = 1 TO 7
          CIRCLE (i% * 40 - 5, 10), 10, VAL(MID$(BallColors$, i% * 2 - 1, 2))
     NEXT i%
     LOCATE 12, 5: PRINT "PLEASE SELECT YOUR BALL COLOR."

     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     'ArrowX% and ArrowY% store the coordinates of the selection indicator.
     'By adjusting the ArrowY% value inside of a loop and a random color,
     'the indicator appears to be pointing at the selected ball and flashing.
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     ArrowX% = 5                                            'START X-COORD
     DO
          ArrowY% = 8                                       'START Y-COORD
          DO
               ArrowY% = ArrowY% - 1                        'MOVE ARROW UP
               IF ArrowY% = 4 THEN ArrowY% = 7              'RESET ARROW
              
               COLOR INT(RND * 15) + 1                      'RANDOM COLOR
               LOCATE ArrowY%, ArrowX%: PRINT CHR$(127);    'DRAW ARROW
               Speed HSS.S1                                 'SHORT PAUSE
               LOCATE ArrowY%, ArrowX%: PRINT " ";          'ERASE ARROW
              
               k$ = UCASE$(INKEY$)                          'CHECK KEYPRESS
          LOOP UNTIL k$ <> ""                               'EXIT ON KEYPRESS
        
          '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
          'If the user hits left or right arrow keys, adjust ArrowX% if able.
          '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
          SELECT CASE k$
               CASE CHR$(0) + "K"
                    IF ArrowX% > 5 THEN ArrowX% = ArrowX% - 5
               CASE CHR$(0) + "M"
                    IF ArrowX% < 35 THEN ArrowX% = ArrowX% + 5
          END SELECT
     LOOP UNTIL k$ = CHR$(13)

     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     'Return to Screen Mode 0.
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     SCREEN 0
     WIDTH 80, 25
    
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     'Set the return value of the function to the appropriate color value.
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     GetBallColor% = VAL(MID$(BallColors$, (ArrowX% \ 5) * 2 - 1, 2))
END FUNCTION

FUNCTION GetLane%
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     'This function returns the lane down which the user rolls their ball.
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     WHILE INKEY$ <> "": WEND                          'CLEAR KEYBOARD BUFFER

     x% = 41                                           'WHERE BALL IS
     xAdj% = 1                                         'DIRECTION IT'S GOING
    
     DO                                                '-----START LOOP------
          x% = x% + xAdj%                              'MOVE BALL
          IF x% = 41 OR x% = 219 THEN xAdj% = -xAdj%   'REVERSE DIRECTION

          CIRCLE (x%, 190), 10, Ball.c                 'DRAW BALL IN COLOR
          Speed HSS.S2                                 'PAUSE SHORT MOMENT
          CIRCLE (x%, 190), 10, 0                      'ERASE BALL

          k$ = INKEY$                                  'CHECK FOR KEYPRESS
     LOOP UNTIL k$ = CHR$(13) OR k$ = CHR$(27)         '-END @ ENTER OR ESC--
     IF k$ = CHR$(27) THEN QuitFlag% = 1               'IF ESC, SET QuitFlag%

     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     'This next formula looks complex.  Basically, we want the ball's x-coord
     'to be: 50, 70, 90, 110, 130, 150, 170, 190, or 210.  This formula says:
     '
     '    if ball is between 40 and 60, make it 50
     '    if ball is between 60 and 80, make it 70
     '
     '                   etc, etc...
     '
     '    if ball is between 180 and 200, make it 190
     '    if ball is between 200 and 220, make it 210
     '
     'Again, let me know if you have trouble following how this works.
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    
     GetLane% = ((x% - 40) \ 20) * 20 + 50             'CENTER BALL IN LANE
END FUNCTION

FUNCTION GetPower%
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     '                         *** NOTE TO JOHN ***
     '
     ' I spent a while looking through your code and couldn't figure
     'out how the power of the ball affected anything.  So I just left
     'that part of of the re-written code.  However, if you want it in
     'here, either let me know, or write it in this area. =)
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
END FUNCTION

SUB HitPin (n%)
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     'This routine uses recursion to calculate your score for this roll. It
     'it passed the value of the pin your ball hit, then checks to see is the
     'pin is standing or not.  If it is not, nothing happens and your score
     'is unchanged.  If the pin is standing, it knocks it over, then calls
     'HitPin (itself) on any pins that first pin might have bumped into.
     'The variable adjScore% keeps track of the total pin count of the roll.
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     'First of all, check to see whether a strike or spare was rolled, since
     'either of these results in a special score value (i.e. not just the
     'number of pins that got knocked over).
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     IF n% = 10 THEN                                   'SPARE OR STRIKE!

          IF Roll% = 1 THEN                            '1ST ROLL, SO STRIKE
               CALL StrikeOrSpare                      '..FLASH MESSAGE
               adjScore% = 30                          '..SET adjScore% TO 30
               Roll% = 2                               '..NEXT ROLL SKIPPED

          ELSE                                         '2ND ROLL, SO SPARE.
               CALL StrikeOrSpare                      '..FLASH MESSAGE
               adjScore% = 20                          '..SET adjScore% TO 20
          END IF
    
    
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     'If the 10-pin (front pin) is not hit, there is no strike or spare. So
     'next we check to see if the pin is standing.  If so, make it knocked
     'down, erase it from screen, and increase adjScore% variable.
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     ELSE                                              'NO SPARE OR STRIKE!

          IF Pin(n%).Up = 1 THEN                       'THE PIN IS STANDING
               Pin(n%).Up = 0                          '..KNOCK IT OVER
               CIRCLE (Pin(n%).x, Pin(n%).y), 5, 0     '..ERASE IT
               adjScore% = adjScore% + 1               '..ADD 1 TO adjScore%

               '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
               'Since the pin was standing, we need to see what other pins it
               'might knock into.  For each one of those, we call HitPin sub.
               '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
              
               SELECT CASE n%           'WHICH PIN ARE WE LOOKING AT?
                    CASE 5              '..PIN 5
                         HitPin 1       '  ..PIN 5 HITS PIN 1
                         HitPin 2       '  ..PIN 5 HITS PIN 2
                    CASE 6              '..PIN 6
                         HitPin 2       '  ..PIN 6 HITS PIN 2
                         HitPin 3       '  ..PIN 6 HITS PIN 3
                    CASE 7              '..PIN 7
                         HitPin 3       '  ..PIN 7 HITS PIN 3
                         HitPin 4       '  ..PIN 7 HITS PIN 4
                    CASE 8              '..PIN 8
                         HitPin 5       '  ..PIN 8 HITS PIN 5
                         HitPin 6       '  ..PIN 8 HITS PIN 6
                    CASE 9              '..PIN 9
                         HitPin 6       '  ..PIN 9 HITS PIN 6
                         HitPin 7       '  ..PIN 9 HITS PIN 7
               END SELECT

               '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
               'Recursion is kind of tricky to understand at first.  Imagine
               'if you hit pin 9 first.  Well, you get 1 point for that, and
               'also hit pins 6 and 7.  Well, when HitPin 6 and 7 get called,
               'those each give you one point.  HitPin 6 then hits 2 and 3,
               'while HitPin 7 hits pins 3 and 4.  But because HitPin 6
               'already called HitPin 3, by the time HitPin 7 calls HitPin 3,
               'Pin 3 is already knocked over. Let me know if you have any
               'trouble following the logic here. =)
               '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
          END IF
     END IF
END SUB

SUB Initialize
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     'Seed the RND() function, set the screen mode.
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     RANDOMIZE TIMER                              'SEED THE RND() FUNCTION
     SCREEN 0                                     '\
     WIDTH 80, 25                                 ' > SET & CLEAR SCREEN
     CLS                                          '/

     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     'Initialize the x- and y-coordinates of the 10 pins and QuitFlag%
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     FOR i% = 1 TO 10                             '---START LOOP FIRST PIN---
          READ Pin(i%).x                          'READ X-COORD FROM DATA
          READ Pin(i%).y                          'READ Y-COORD FROM DATA
     NEXT i%                                      '---END LOOP @ TENTH PIN---

     QuitFlag% = 0                                'INITIALIZE QuitFlag% TO 0

     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     'Because different computers will run this game at different speeds, we
     'need to figure out how fast this computer is running it, so that we can
     'make sure pauses within the program always pause for the same length of
     'time.  To do this, we need to see how many loops this computer goes
     'through in one second.  We will save this number as OneSecond& and use
     'it for all calls to the Pause() sub in the game code.
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     PRINT "Determining computer speed...";       'NOTIFY USER OF SPEED TEST
     MarkedTime# = TIMER                          'MARK START TIME
     FOR t& = 1 TO 2000000                        '---LOOP 2 MILLION TIMES---
     NEXT t&                                      '---------END LOOP---------
     OneSecond& = 2000000 / (TIMER - MarkedTime#) 'CALCULATE LOOPS PER SECOND
     PRINT "Done! OneSecond&="; OneSecond&        'NOTIFY USER TEST COMPLETED
END SUB

SUB Instructions
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     'Explain to the user how to play.
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     CLS
     PRINT "BOWLING"
     PRINT "CREATED BY JOHN KREITLOW"
     PRINT "IN ASSOCIATION WITH RADIUM-V"
     LOCATE 5, 18: PRINT "BASED ON ACME SOFTWARE'S `BOWLIN' FOR THE TI-83"
     PRINT
     LOCATE 7, 31: PRINT "PRESS SPACE TO START"
     LOCATE 8, 31: PRINT "PRESS ESCAPE TO QUIT"
     LOCATE 9, 32: PRINT "+---------------+"
     LOCATE 10, 32: PRINT "| LANE    RULES |"
     LOCATE 11, 32: PRINT "+---------------+"
     PRINT
     PRINT "STRIKE = 30 POINTS"
     PRINT "SPARE = 20 POINTS"
     PRINT "HIT `ENTER' AT WANTED SPACE ON THE LANE TO SELECT IT."
     PRINT "SELECT STRENGTH, INDICATED AT BASE OF POWER METER. CHOOSE"
     PRINT "QUICKLY, BECAUSE YOU WILL MISS A TURN IF YOU TAKE TOO LONG!"

     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     'Show the user the current high score.
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     PRINT "HI-SCORE: "; HSS.UserHigh;
     PRINT "BY "; HSS.UserName                          'SHOW THE HIGH SCORE
    
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     'Wait for a keypress.  Spacebar will start the game.  Escape will quit.
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     DO                                                '-----START LOOP------
          k$ = UCASE$(INKEY$)                          'MONITOR KEYPRESSES
     LOOP UNTIL k$ = " " OR k$ = CHR$(27)              '-END AT SPACE OR ESC-
     IF k$ = CHR$(27) THEN QuitFlag% = 1               'IF ESC, SET QuitFlag%
END SUB

SUB Intro
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     'Draw an intro screen showing a ball rolling a strike.
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     CLS                                     'CLEAR THE SCREEN
     LOCATE 2, 37: PRINT "O O O O"           '\
     LOCATE 3, 37: PRINT " O O O"            ' \ DRAW A RACK OF PINS
     LOCATE 4, 37: PRINT "  O O"             ' / AT TOP OF THE SCREEN
     LOCATE 5, 37: PRINT "   O"              '/

     FOR i% = 23 TO 1 STEP -1                '---START LOOP BALL AT BOTTOM---
          LOCATE i%, 37                      'POSITION CURSOR AT BALL'S SPOT
          PRINT "   0   ";                   'DRAW ERASING LINE WITH BALL
          Speed HSS.S3                       'SHORT PAUSE
          LOCATE i%, 40                      'POSITION CURSOR AT BALL'S SPOT
          PRINT " ";                         'ERASE THE BALL
     NEXT i%                                 '---END LOOP WHEN BALL AT TOP---
END SUB

SUB ResetPins
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     'Set all 10 pins so that they are standing.
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     FOR i% = 1 TO 10                             '---START LOOP 1 THRU 10---
          Pin(i%).Up = 1                          'SET THIS PIN TO STANDING
     NEXT i%                                      '------END LOOP AT 10------
END SUB

SUB RollBall
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     'Roll ball down the lane, see what pins are hit, and determine scoring.
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    
     FOR y% = 190 TO -5 STEP -1              '---START LOOP BALL AT BOTTOM---
          CIRCLE (Ball.x, y%), 10, Ball.c    'DRAW BALL IN PICKED COLOR
          Speed HSS.S4                       'PAUSE A BRIEF MOMENT
          CIRCLE (Ball.x, y%), 10, 0         'COVER BALL WITH BLACK CIRCLE
     NEXT y%                                 '---END LOOP WHEN BALL AT TOP---

     adjScore% = 0                           'AMOUNT OF POINTS FOR THIS ROLL
     SELECT CASE Ball.x                      '\
          CASE 70: HitPin 1                  ' \
          CASE 90: HitPin 5                  '  `  DEPENDING ON BALL'S LANE
          CASE 110: HitPin 8                 '  |  DETERMINE WHICH PIN WAS
          CASE 130: HitPin 10                '   > STRUCK FIRST. PASS THIS
          CASE 150: HitPin 9                 '  |  PIN # TO THE HitPin SUB
          CASE 170: HitPin 7                 '  '  WHICH WILL SET adjScore%
          CASE 190: HitPin 4                 ' /
     END SELECT                              '/
     Score% = Score% + adjScore%             'ADD ROLL SCORE TO TOTAL SCORE
END SUB

SUB Speed (c%)
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     'Speed of c% means pause for (OneSecond& / c%) loops.
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     DEF SEG = 0
     k = PEEK(&H417)
     IF (k AND 4) THEN c% = c% - 1
     IF (k AND 8) THEN c% = c% + 1
     IF c% < 1 THEN c% = 1
     t& = OneSecond& / c%
     FOR Counter& = 1 TO t&                            '---START LOOP AT 1---
     NEXT Counter&                                     '---END LOOP AT t&----
END SUB

SUB StrikeOrSpare
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     'User has bowled a strike or a spare.  Show them a framed message.
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     CLS                                          'CLEAR THE SCREEN
     COLOR 7                                      'SET COLOR: GREY
     LOCATE 5, 13: PRINT "+------------+"         'TOP OF FRAME
     LOCATE 6, 13
     IF Roll% = 1 THEN                            'CHECK WHICH ROLL IT IS...
          PRINT "|   STRIKE!  |"                  ' ..FIRST ROLL, SO STRIKE
     ELSE
          PRINT "|   SPARE!   |"                  ' ..SECOND ROLL, SO SPARE
     END IF
     LOCATE 7, 13: PRINT "+------------+"         'BOTTOM OF FRAME
     LOCATE 9, 13: PRINT " PRESS  SPACE"          'SHOW EXIT CONDITION
    
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     'Highlight the frame with moving yellow stars until they hit spacebar.
     '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     FlashHi% = 13                                'TOP STAR
     FlashLo% = 25                                'BOTTOM STAR
     DO                                           '--------START LOOP--------
          FlashHi% = FlashHi% + 1                 'MOVE TOP STAR RIGHT
          FlashLo% = FlashLo% - 1                 'MOVE BOTTOM STAR LEFT
        
          IF FlashHi% = 25 THEN FlashHi% = 14     'RESET TOP STAR
          IF FlashLo% = 13 THEN FlashLo% = 24     'RESET BOTTOM STAR
        
          COLOR 14                                'SET COLOR: YELLOW
          LOCATE 5, FlashHi%: PRINT "-*"          'DRAW TOP STAR
          LOCATE 7, FlashLo%: PRINT "*-"          'DROP BOTTOM STAR
        
          Speed HSS.S5                            'PAUSE BRIEF MOMENT
        
          COLOR 7                                 'SET COLOR: GREY
          LOCATE 5, FlashHi%: PRINT "--"          'REDRAW TOP FRAME
          LOCATE 7, FlashLo%: PRINT "--"          'REDRAW BOTTOM FRAME
     LOOP UNTIL INKEY$ = " "                      '---END LOOP UPON SPACE----
END SUB
Reply
#39
Okay, we get it. If you try really hard you can come up with a programming example where a GOTO statement can save you a few comparisons. This has been covered many times, and the same example is always used (it's already been given once in this thread alone). I personally have never written code that involved more than.. I don't know.. three? four? nested FORs, and in those you can typically combine your NEXT statements and still use an EXIT FOR to kick out of multiple loops (see my example above, in this same thread).

I'm sorry for coming across as bitchy. I get tired of hearing the same arguments over and over. Can't we all agree that GOTO can be used in rare circumstances by careful coders to make code more efficient, but is unnecessary in most programs?

This thread is about a bowling program that had lots of problems. Use of GOTO was just one of them.

*peace*

Meg.

edit: MAC, I like that we're working on the same code. I actually *added* the 2nd file access, just to remove two variables used in the program (high score+high score name). I like the idea of being able to adjust the speed, since my code to test system speed was really only an approximation. There's prolly an easier way to do it (like adjusting the value of OneSecond&, or the divisor passed to the Pause() routine).

This is being nitpicky, but we should prolly try to keep the entirety of the code out of the forum posts. I try to post links to long code, instead of including the entire code in my post.
Reply
#40
Exactly. But the sentence "GOTO is evil and should be avoided" is not complete.

The complete sentence should be "GOTO is dangerous and should be avoided if there's a better solution".

I know that I always post the same example, but it's 'cause it's _the_ example. The linux kernel is full of stuff like that, full of GOTOs. It can save you a lot of code if used correctly, and a lot of logic and time as well.

And you mention EXIT FOR... Note that EXIT FOR is just a GOTO with a different look.

To me it's the same

Code:
FOR i% = 1 TO 10000
   IF blah% THEN GOTO outside
NEXT i%

outside:

Code:
FOR i% = 1 TO 10000
   IF blah% THEN EXIT FOR
NEXT i%

If GOTO means spaghetti, EXIT FOR is the same. As BASIC doesn't allow to add a conditional expression in the FOR, the non-spaghetti, structured code would be:

Code:
i% = 1
DO
   ...
   i% = i% + 1
LOOP WHILE i% <= 10000 AND NOT blah%

Exitting a loop with a GOTO is the same as exitting it with a EXIT FOR. Think about it. So if you call using GOTO "spaghetti code", yours is as well, as you are using EXIT FOR.

The EXIT FOR way may look cleaner, as you don't use a label, but it gets translated to the same assembly code. The collateral effects can be the same. The speed is the same. It just looks different.
SCUMM (the band) on Myspace!
ComputerEmuzone Games Studio
underBASIC, homegrown musicians
[img]http://www.ojodepez-fanzine.net/almacen/yoghourtslover.png[/i
Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)